I have a question about sorting String[] arrays using the Insertion Sort Algorithm in Java. I do realize that my question may very well be easier to complete using a different algorithm, but I am attempting to learn how everything works with this one first.
Basically, I am attempting to sort an array of strings using the algorithm. To do this, I compare char values from the array of strings so I am able to use standard > and == operators because comparing values this way (like you would with ints) is naturally very simple.
I have a solution I am working through where I sort an array of strings by the first 2 char values found at each array index, but I am starting to realize that what I have done is not a very robust solution because strings in an array can easily have values that are 'longer' than each other which would not make my sorting very accurate for longer strings with similar values.
With that in mind, can someone suggest (going along with the code I wrote below) how I would go about dynamically comparing char values created from various strings to sort the original string value?
So...
A: ...I don't run into NullPointer Exceptions comparing values from different sized strings
B: ...every char value is compared from the string, irregardless of size, so I can sort the original array of strings accurately)
public String[] sortArrayOfStrings(String[] array){
//NOT COMPLETE, ONLY SORTS BASED ON FIRST & SECOND CHAR OF STRING INDEX
//BASED ON INSERTION SORT ALGORITHM
int length = array.length;
String value;
int index;
for(int a = 1; a < length; a++){
char currentCharValue = array[a].charAt(0);//USE '[a]' not '[index]'
value = array[a];
index = a;
if(currentCharValue == array[a - 1].charAt(0) ){//IF FIRST CHAR == PREVIOUS
while (index > 0 && array[index - 1].charAt(1) > array[index].charAt(1)){
array[index] = array[index - 1];
index = index - 1;
}
}else{
while (index > 0 && array[index - 1].charAt(0) > currentCharValue){
array[index] = array[index - 1];
index = index - 1;
}
}
array[index] = value;
}
return array;
}
Example array that works as expected because of 2 char check:
String[] arr = {"zz", "bb", "cb", "ba","za", "zb", "cz", "ab","aa"};
Example array that would fail to sort correctly because of extra chars:
String[] arr = {"bbz", "bba", "abz","abc"};
I know the above array fails to sort correctly because of the hardcoded 'check' of 2 chars, I am trying to remove the need to hardcode the check.
Try using the String.CompareTo(String s) method. It's a lot like the comparison operators that you have been using, except it will evaluate to an integer.
String str1 = "Cat";
String str2 = "Dog";
int sCompare = str1.CompareTo(str2);
if sCompare == 0, then the Strings are the "same"
if sCompare > 0, then str1 > str2 (alphabetically)
if sCompare < 0, then str2 > str1 (alphabetically)
Edit:
For clarity, in the case of the above example, sCompare would evaluate to a negative value.
If you really want to do it using chars comparsion the best way is to create separate method to compare these Strings.
Inside a isSmallerThan() while loop increments currentIndex until it's not out of bound for any argument and until chars are same.
Then if statement check whether currentIndex got out of bounds for at least one string, it can happen for inputs like e.g.:
(aaaaa, aa),
(aaabb, aaa),
(aaa, aaa).
Then we must decide what is smaller by length comparsion.
For the case of insertion sort algorithm we do not care that (aaa, aaa) are the same Strings, we can just return that this is false and it'll interrupt a while loop inside sortArrayOfStrings method.
Else we know that chars are different and we simply compare them.
String[] sortArrayOfStrings(String[] array){
int length = array.length;
String value;
int index;
for(int a = 1; a < length; a++){
value = array[a];
index = a;
while(index > 0 && isSmallerThan(value, array[index-1])) {
array[index] = array[index - 1];
--index;
}
array[index] = value;
}
return array;
}
boolean isSmallerThan(String left, String right) {
int curIndex = 0;
while (curIndex < left.length()
&& curIndex < right.length()
&& left.charAt(curIndex) == right.charAt(curIndex)){
++curIndex;
}
if (curIndex == left.length() || curIndex == right.length())
return left.length() < right.length();
else
return left.charAt(curIndex) < right.charAt(curIndex);
}
But as people said before me it would be better to use compareTo or compareToIgnoreCase method from String library. To make this work just change
isSmallerThan(value, array[index-1])
into
array[index-1].compareToIgnoreCase(value) > 0.
Using compareTo() method, implementation of insertion sort algorithm can look like this:
class InsertionSorter {
public String[] sortArrayOfStrings(String[] array) {
for (int i = 1; i < array.length; i++) {
String element = array[i];
int j;
for (j = i - 1; j >= 0 && element.compareTo(array[j]) <= 0; j--)
array[j + 1] = array[j];
array[j + 1] = element;
}
return array;
}
}
Example tests:
public class InsertionSorterTest {
#Test
public void shouldSortTwoLetterWords() {
String[] arr = {"zz", "bb", "cb", "ba", "za", "zb", "cz", "ab", "aa"};
String[] sortedArray = new InsertionSorter().sortArrayOfStrings(arr);
Assert.assertEquals(sortedArray, new String[]{"aa", "ab", "ba", "bb", "cb", "cz", "za", "zb", "zz"});
}
#Test
public void shouldSortLongerWords() {
String[] arr = {"bbz", "bba", "abz", "abc"};
String[] sortedArray = new InsertionSorter().sortArrayOfStrings(arr);
Assert.assertEquals(sortedArray, new String[]{"abc", "abz", "bba", "bbz"});
}
}
Related
Write a function:
class Solution{
public int solution(int[] A);
}
that, given an array A of N integers, returns the smallest positive integer(greater than 0)
that does not occur in A.
For example, given A = [1,3,6,4,1,2], the function should return 5.
Given A = [1,2,3], the function should return 4.
Given A = [-1, -3], the function should return 1.
Write an efficient algorithm for the following assumptions.
N is an integer within the range [1..100,000];
each element of array A is an integer within the range [-1,000,000..1,000,000].
I wrote the following algorithm in Java:
public class TestCodility {
public static void main(String args[]){
int a[] = {1,3,6,4,1,2};
//int a[] = {1,2,3};
//int b[] = {-1,-3};
int element = 0;
//checks if the array "a" was traversed until the last position
int countArrayLenght = 0;
loopExtern:
for(int i = 0; i < 1_000_000; i++){
element = i + 1;
countArrayLenght = 0;
loopIntern:
for(int j = 0; j < a.length; j++){
if(element == a[j]){
break loopIntern;
}
countArrayLenght++;
}
if(countArrayLenght == a.length && element > 0){
System.out.println("Smallest possible " + element);
break loopExtern;
}
}
}
}
It does the job but I am pretty sure that it is not efficient. So my question is, how to improve this algorithm so that it becomes efficient?
You should get a grasp on Big O, and runtime complexities.
Its a universal construct for better understanding the implementation of efficiency in code.
Check this website out, it shows the graph for runtime complexities in terms of Big O which can aid you in your search for more efficient programming.
http://bigocheatsheet.com/
However, long story short...
The least amount of operations and memory consumed by an arbitrary program is the most efficient way to achieve something you set out to do with your code.
You can make something more efficient by reducing redundancy in your algorithms and getting rid of any operation that does not need to occur to achieve what you are trying to do
Point is to sort your array and then iterate over it. With sorted array you can simply skip all negative numbers and then find minimal posible element that you need.
Here more general solution for your task:
import java.util.Arrays;
public class Main {
public static int solution(int[] A) {
int result = 1;
Arrays.sort(A);
for(int a: A) {
if(a > 0) {
if(result == a) {
result++;
} else if (result < a){
return result;
}
}
}
return result;
}
public static void main(String args[]){
int a[] = {1,3,6,4,1,2};
int b[] = {1,2,3};
int c[] = {-1,-3};
System.out.println("a) Smallest possible " + solution(a)); //prints 5
System.out.println("b) Smallest possible " + solution(b)); //prints 4
System.out.println("c) Smallest possible " + solution(c)); //prints 1
}
}
Complexity of that algorithm should be O(n*log(n))
The main idea is the same as Denis.
First sort, then process but using java8 feature.
There are few methods that may increase timings.(not very sure how efficient java 8 process them:filter,distinct and even take-while ... in the worst case you have here something similar with 3 full loops. One additional loop is for transforming array into stream). Overall you should get the same run-time complexity.
One advantage could be on verbosity, but also need some additional knowledge compared with Denis solution.
import java.util.function.Supplier;
import java.util.stream.IntStream;
public class AMin
{
public static void main(String args[])
{
int a[] = {-2,-3,1,2,3,-7,5,6};
int[] i = {1} ;
// get next integer starting from 1
Supplier<Integer> supplier = () -> i[0]++;
//1. transform array into specialized int-stream
//2. keep only positive numbers : filter
//3. keep no duplicates : distinct
//4. sort by natural order (ascending)
//5. get the maximum stream based on criteria(predicate) : longest consecutive numbers starting from 1
//6. get the number of elements from the longest "sub-stream" : count
long count = IntStream.of(a).filter(t->t>0).distinct().sorted().takeWhile(t->t== supplier.get()).count();
count = (count==0) ? 1 : ++count;
//print 4
System.out.println(count);
}
}
There are many solutions with O(n) space complexity and O(n) type complexity. You can convert array to;
set: array to set and for loop (1...N) check contains number or not. If not return number.
hashmap: array to map and for loop (1...N) check contains number or not. If not return number.
count array: convert given array to positive array count array like if arr[i] == 5, countArr[5]++, if arr[i] == 1, countArr[1]++ then check each item in countArr with for loop (1...N) whether greate than 1 or not. If not return it.
For now, looking more effective algoritm like #Ricola mentioned. Java solution with O(n) time complexity and O(1) space complexity:
static void swap(final int arr[], final int i,final int j){
final int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
static boolean isIndexInSafeArea(final int arr[], final int i){
return arr[i] > 0 && arr[i] - 1 < arr.length && arr[i] != i + 1 ;
}
static int solution(final int arr[]){
for (int i = 0; i < arr.length; i++) {
while (isIndexInSafeArea(arr,i) && arr[i] != arr[arr[i] - 1]) {
swap(arr, i, arr[i] - 1);
}
}
for (int i = 0; i < arr.length; i++) {
if (arr[i] != i + 1) {
return i+1;
}
}
return arr.length + 1;
}
I need to write function that gets 3 params(int num, int k, int nDigit).
The function get number and replace the digit inside the number in k index by nDigit.
for example:
int num = 5498
int k = 2
int nDigit= 3
the result is num = 5398
My question is how can I implement it?I undastand that the best way to convert the num to string and then just replace char on specific index by nDigit char.
But is there any way to implement it?Without
public int changeDigit(int num, int k, int nDigit){
k = pow(10,k);
double saved = num%k; // Save digits after
num = num - (num%(k*10)); //Get what's before k
return ((int) (num + (nDigit*k) + saved));
}
I won't do your homework for you, but here's some hints:
Convert integer to string:
String s = Integer.toString(1234);
Enumerating a string:
for (i = 0; i < s.length; i++)
{
char c = s.charAt(i);
}
String building (a little less efficient without the StringBuilder class)
char c = '1';
String s = "3";
String j = "";
j = j + c;
j = j + s; // j is now equal to "13"
String back to integer:
int val = Integer.parseInt("42");
You can use a StringBuilder. It's easier to see what you're doing and you don't need to perform mathematics, only adjust the characters in their positions. Then convert it back to int.
public class Main {
static int swapParams(int num, int k, int nDigit) {
StringBuilder myName = new StringBuilder(Integer.toString(num));
myName.setCharAt(k-1, Integer.toString(nDigit).charAt(0));
return Integer.parseInt(myName.toString());
}
public static void main(String[] args) {
System.out.println(swapParams(5498, 2, 3));
}
}
http://ideone.com/e4MF6m
You can do it like this:
public int func(int num, int k, int nDigit) {
String number = String.valueOf(num);
return Integer.parseInt(number.substring(0, k - 1) + nDigit + number.substring(k, number.length()));
}
This function takes the first characters of the number without the k'th number and adds the nDigit to it. Then it adds the last part of the number and returns it as an integer number.
This is my javascript solution.
const solution = numbers => { //declare a variable that will hold
the array el that is not strictly ascending let flawedIndex;
//declare a boolean variable to actually check if there is a flawed array el in the given array let flawed = false;
//iterate through the given array for(let i=0; i<numbers.length; i++) {
//check if current array el is greater than the next
if(numbers[i] > numbers[i+1])
{
//check if we already set flawed to true once.
//if flawed==true, then return that this array cannot be sorted
//strictly ascending even if we swap one elements digits
if(flawed) {
return false;
}
//if flawed is false, then set it to true and store the index of the flawed array el
else {
flawed = true;
flawedIndex = i;
}
}
}
//if flawed is still false after the end of the for loop, return true //where true = the array is sctrictly ascending if(flawed ==
false) return true;
//if flawed==true, that is there is an array el that is flawed if(flawed){
//store the result of calling the swap function on the digits of the flawed array el
let swapResult = swap(flawedIndex,numbers);
//if the swapresult is true, then return that it is ascending
if (swapResult == true) return true; }
//else return that its false return false; }
const swap = (flawIndex, numbers) => {
let num = numbers[flawIndex];
//convert the given array el to a string, and split the string based on '' let numToString = num.toString().split('');
//iterate through every digit from index 0 for(let i=0;
i<numToString.length; i++) {
//iterate from every digit from index 1
for(let j=i+1; j<numToString.length; j++) {
//swap the first index digit with every other index digit
let temp = numToString[i];
numToString[i] = numToString[j]
numToString[j] = temp;
console.log(numToString)
//check if the swapped number is lesser than the next number in the main array
//AND if it is greater than the previous el in the array. if yes, return true
let swappedNum = Number(numToString.join(''));
if(swappedNum < numbers[flawIndex + 1] && swappedNum > numbers[flawIndex-])
{
return true;
}
} } //else return false return false; }
console.log("the solution is ",solution([1, 3, 900, 10]))
I want to sort the strings in the array, by alphabetizing them, but I get an error with argument types.
public class BubbleSort {
public static String[] sortStringArray(String[] stringArray) {
int s = stringArray.length;
String temp;
for (int i = 0 ; i < s; i++) {
for (int j = 1; j < (s - i); j++) {
String a1 = stringArray[j - 1];
String b1 = stringArray[j];
int result = a1.compareTo(b1);
if (result > stringArray[j]) {
temp = stringArray[j - 1];
stringArray[j - 1] = stringArray[j];
stringArray[j] = temp;
}
}
}
return stringArray;
}
}
Since you're calling compareTo(Object) on Strings, you need to check then if the result is bigger than zero:
if (0 < result) { // i.e. a1 is smaller than b1
//swap values as usual
}
To sort a String array by natural ordering you can use Arrays.stream
eg:
String[] s = {"b", "c", "a", "aaa", "abc"};
s = Arrays.stream(s).sorted().toArray(String[]::new);
gives s= [a, aaa, abc, b, c]
if (result > stringArray[j])
result is an integer, stringarray[j] is a string.
You can't compare with integer like that, if your string is an integer like stinrgArray[j] value is "11" and you want to compare it you need to parse it first to integer:
if(result > Integer.parseInt(stringArray[j]))
My method accepts two arrays of integers and returns true if
The arrays are the same length and
each a.element is less than the b.element of the same index.
It works for all my test cases except when int[] a = {1, 2, 3} and int[] b = {4, 5, 1}. It returns true even though a[2] > b[2]. The digitDifference check isn't working correctly but I can't see the error.
public static boolean allLess(int[] a, int[] b) {
int i = 0;
boolean sameLength = (a.length == b.length);
boolean digitDifference = (a[i] < b[i]);
for (i = 0; i <= a.length - 1; i++) {}
return (sameLength && digitDifference);
}
Your method only compares the first element in each array - the comparison is done outside the for loop (which is empty!) instead of inside it. Move it there, and you should be OK.
It's worth noting that using the early return idiom would help produce much easier to read code in this scenario, as you don't need to continue "dragging" the current state with you, just fail-fast when one of the conditions is broken:
public static boolean allLess(int[] a, int[] b) {
if (a.length != b.length) {
return false;
}
for (i = 0; i <= a.length - 1; i++) {
if (a[i] >= b[i]) {
return false;
}
}
return true;
}
Your for loop does nothing, so you are only comparing the elements in the first index of the arrays.
Your code should look something like this :
public static boolean allLess(int[] a, int[] b) {
boolean sameLength = (a.length == b.length);
if (!sameLength)
return false;
boolean digitDifference = true;
for (int i = 0; i <= a.length - 1 && digitDifference; i++) {
digitDifference = (a[i] < b[i]);
}
return digitDifference;
}
Now the for loop compares each pair of elements having the same index, and terminates once it finds a pair that violates your requirement that (a[i] < b[i]).
Another equivalent implementation without the flags :
public static boolean allLess(int[] a, int[] b) {
if (a.length != b.length)
return false;
for (int i = 0; i <= a.length - 1; i++) {
if (a[i] >= b[i])
return false;
}
return true;
}
digitDifference is initialized before the loop, and compare the first elements of both arrays, since i's value is 0 at this point. You never compare the other elements of the array. The comparison must be done inside the loop.
BTW, your loop body doesn't even have a single instruction.
You have a check to compare the length of both arrays, but you only act upon it at the end of the method. Java, like any other language allows you to have multiple return statements in a method, so my suggestion would be to return from the method as soon as you perform the check:
if (a.length != b.length)
return false;
Second, the digitDifference statement in your code is only evaluated once, with the first elements in your arrays. I believe, you wanted the for-loop to perform the comparison multiple times on each element in the array, however, you left the body of the loop empty.
for (i = 0; i <= a.length - 1; i++) {
if(a[i] >= b[i])
return false;
}
Again, my suggestion is to return as soon as you find that one of the elements breach you constraint. And just have a return true; after the for-loop, which will indicate that all of the elements satisfy the constraint a[i] >= b[i].
List<String> list1 = List.of("Banana", "Watermelon", "Carrot");
List<String> list2 = List.of("Apple", "Plum", "Orange");
System.out.println(list1.stream().anyMatch(list2::contains));
Output: false
List<String> list1 = List.of("Banana", "Watermelon", "Carrot");
List<String> list2 = List.of("Apple", "Plum", "Orange", "Watermelon");
System.out.println(list1.stream().anyMatch(list2::contains));
Output: true
new programmer here. I watched a video which displayed a recursive algorithm for LCS(longest common substring). The program only returned an int which was the length of the LCS between the two strings. I decided as an exercise to adapt the algorithm to return the string itself. Here is what I came up with, and it seems to be right, but I need to ask others more experienced if there are any bugs;
const int mAX=1001; //max size for the two strings to be compared
string soFar[mAX][mAX]; //keeps results of strings generated along way to solution
bool Get[mAX][mAX]; //marks what has been seen before(pairs of indexes)
class LCS{ //recursive version,use of global arrays not STL maps
private:
public:
string _getLCS(string s0,int k0, string s1,int k1){
if(k0<=0 || k1<=0){//base case
return "";
}
if(!Get[k0][k1]){ //checking bool memo to see if pair of indexes has been seen before
Get[k0][k1]=true; //mark seen pair of string indexs
if(s0[k0-1]==s1[k1-1]){
soFar[k0][k1]=s0[k0-1]+_getLCS(s0,k0-1,s1,k1-1);//if the char in positions k0 and k1 are equal add common char and move on
}
else{
string a=_getLCS(s0,k0-1,s1,k1);//this string is the result from keeping the k1 position the same and decrementing the k0 position
string b=_getLCS(s0,k0,s1,k1-1);//this string is the result from decrementing the k1 position keeping k0 the same
if(a.length()> b.length())soFar[k0][k1]=a;//the longer string is the one we are interested in
else
soFar[k0][k1]=b;
}
}
return soFar[k0][k1];
}
string LCSnum(string s0,string s1){
memset(Get,0,sizeof(Get));//memset works fine for zero, so no complaints please
string a=_getLCS(s0,s0.length(),s1,s1.length());
reverse(a.begin(),a.end());//because I start from the end of the strings, the result need to be reversed
return a;
}
};
I have only been programming for 6 months so I cant really tell if there is some bugs or cases where this algorithm will not work. It seems to work for two strings of size up to 1001 chars each.
What are the bugs and would the equivalent dynamic programming solution be faster or use less memory for the same result?
Thanks
Your program is not correct. What does it return for LCSnum("aba", "abba")?
string soFar[mAX][mAX] should be a hint that this is not a great solution. A simple dynamic programming solution (which has logic that you almost follow) has an array of size_t which is m*n in size, and no bool Get[mAX][mAX] either. (A better dynamic programming algorithm only has an array of 2*min(m, n).)
Edit: by the way, here is the space-efficient dynamic programming solution in Java. Complexity: time is O(m*n), space is O(min(m, n)), where m and n are the lengths of the strings. The result set is given in alphabetical order.
import java.util.Set;
import java.util.TreeSet;
class LCS {
public static void main(String... args) {
System.out.println(lcs(args[0], args[1]));
}
static Set<String> lcs(String s1, String s2) {
final Set<String> result = new TreeSet<String>();
final String shorter, longer;
if (s1.length() <= s2.length()) {
shorter = s1;
longer = s2;
}else{
shorter = s2;
longer = s1;
}
final int[][] table = new int[2][shorter.length()];
int maxLen = 0;
for (int i = 0; i < longer.length(); i++) {
int[] last = table[i % 2]; // alternate
int[] current = table[(i + 1) % 2];
for (int j = 0; j < shorter.length(); j++) {
if (longer.charAt(i) == shorter.charAt(j)) {
current[j] = (j > 0? last[j - 1] : 0) + 1;
if (current[j] > maxLen) {
maxLen = current[j];
result.clear();
}
if (current[j] == maxLen) {
result.add(shorter.substring(j + 1 - maxLen, j + 1));
}
}
}
}
return result;
}
}