I have to implement the .length method from String class "by hand" and I have no idea and hope you can help somehow.
No other methods or functions are allowed, than:
String.charAt()
String.substring()
String.isEmpty()
Bit-operations &,|, &&,||, <<, >>,>>>, !=, ==
Arithmetic operations
for and while Loop
recursion
if else statement
self created methods (int,String,char,boolean etc.)
self-created Arrays. (no Methods of them)
static void manual_length2(String length) {
//example String length = "Hello" = 5 letters.
int counter = 0;
int i = 0;
char g = ' ';
while(i <= 4 ) { /*4 is the number i already know */
g = length.charAt(i);
counter += 1;
length.substring(1);
++i;
}
System.out.println(counter);
Console: 5
This was my approach, but I'm stuck in the while statement's condition to terminate.
With the example "Hello" i already know that this word has 5 letters, but it needs to fit for all inputs. So i don't know how to express to border-value of the while statement.
Another approach is by recursion, but also, i ask myself how can i express the limit of the recursion.
How can i express:
.... lengthMethod1(String length, int ???) {
if(n == 0) {
return length.charAt(0);
}
else {
return ???? lengthMethod1(length, n - 1);
}
You can loop until the String is empty while removing the first character on each iteration.
static int manual_length(String str) {
int len = 0;
while(!str.isEmpty()){
++len;
str = str.substring(1);
}
return len;
}
This can be converted to a tail-recursive method as well.
static int manual_length(String str) {
return str.isEmpty() ? 0 : 1 + manual_length(str.substring(1));
}
Another approach is by recursion, but also, i ask myself how can i
express the limit of the recursion. How can i express:
Yes, you can do recursively like this:
static int manual_length(String str, int len) {
return str.isEmpty() ? len : manual_length(str.substring(1), len + 1);
}
You use an accumulator variable (i.e., len), that you increment, while removing a char from the string (i.e., str.substring(1)). When you reach the end (i.e., str.isEmpty()) you return the accumulator.
Related
I'm writing a method for my CS151 class called countSevens(n). It Returns count how many digits are 7 in the given number n. This is what I have so far but I'm doing something wrong that I can't figure out.
public int countSevens(int n){
int count = 0;
String strI = Integer.toString(n);
for (int i = 0; i < strI.length(); i++){
if(strI.substring(i).equals("7")){
count++;
}
}
return count;
}
You can do it with java streams
public int countSevens(int n) {
return (int) String.valueOf(n).chars().filter(ch -> ch == '7').count();
}
(int) - cast to an int type, in this particular case it safe to cast long to int, because we can't get a conversation error. In other cases it's better to use Math.toIntExact(long)
String.valueOf(n) - convert to string
chars() - return stream of chars
filter(ch -> ch == '7') - filter all chars that equals to 7
count() - returns the count of elements in this stream
strI.substring(i)
Will return the part of string from i-character to the end.
Use strI.charAt(i) instead
From the definition of String.substring(int):
Returns a string that is a substring of this string. The substring begins with the character at the specified index and extends to the end of this string.
So this will only count the last instance of a 7 in your number, and only if it's the last digit in the number.
Instead, try this:
if(strI.substring(i, i+1).equals("7"))
Or, since you're dealing with ints, you can avoid using strings altogether. n % 10 will get you the last digit, and n /= 10 will bump the entire number right by one digit. That should be enough to get you started on doing this without Strings.
To count the number of 7s in an integer:
int counter = 0;
int number = 237123;
String str_number = String.valueOf(number);
for(char c : str_number.toCharArray()){
if(c == '7'){
counter++;
}
}
You can just use simple arithmetics:
public static int countSevens(int i) {
int count = 0;
for (i = i < 0 ? -i : i; i != 0; count += i % 10 == 7 ? 1 : 0, i /= 10);
return count;
}
But who can read this? Not many, so here is a cleaner solution, applying the same logic:
public static int countSevens(int i) {
int count = 0;
// ignore negative numbers
i = Math.abs(i);
while(i != 0) {
// if last digit is a 7
if(i % 10 == 7) {
// then increase the counter
count++;
}
// remove the last digit
i /= 10;
}
return count;
}
What is the time complexity of the lastIndexOf in java for using it with Strings.
Suppose: int t= s.lastIndexOf(c);
where s is some String and c is s.charAt(0)
Look at the implementation of this method. In both code branches it contain simple iteration over string's internal array:
int i = Math.min(fromIndex, value.length - 1);
for (; i >= 0; i--) {
if (value[i] == ch) {
return i;
}
}
Hence complexity is just O(n), i.e. linear.
For String.lastIndexOf(int) it's linear - O(n).
You at least need to iterate over the whole character sequence, end to start.
And that's what Java does.
Worst case: "abbbbbbbbbb".lastIndexOf('a')
For String.lastIndexOf(String) it's O(n*m) where n is input length and m is parameter length.
In this case, Java iterates end to start and wherever it finds matching last character of the needle it tries to match preceding characters on both sides as well.
As soon as String is implemented as char array it is O(n).
public int lastIndexOf(int ch, int fromIndex) {
if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
// handle most cases here (ch is a BMP code point or a
// negative value (invalid code point))
final char[] value = this.value;
int i = Math.min(fromIndex, value.length - 1);
for (; i >= 0; i--) {
if (value[i] == ch) {
return i;
}
}
return -1;
} else {
return lastIndexOfSupplementary(ch, fromIndex);
}
}
I tried to count words with Streams in Java. Here's what I tried:
public static int countWords(String s) {
return s.chars().reduce((x, y) -> {
if((char)y == ' ')
++x;
return x;
}).orElse(0);
}
But countWords("asd") return 97. Why? I thought that chars returns IntStream which actually consists of chars. So, I just cast it to char. What's wrong?
While your question refers to counting words your code seems to be designed to count spaces. If that's your intention then I would suggest:
input.chars().filter(Character::isSpaceChar).count();
That avoids many of the casting complications you have in your code and you can change it to isWhitespace if that makes more sense for your domain.
If, however, you wish to count words then the simplest solution is to split on whitespace then count non-empty words:
Pattern.compile("\\s+").splitAsStream(input).filter(word -> !word.isEmpty()).count();
I would suggest more functional approach:
public static long countWords(String s) {
return Arrays
.stream(s.split(" "))
.filter(w -> !w.isEmpty())
.count();
}
There are different overloads of the reduce operator:
Optional reduce(BinaryOperator accumulator)
T reduce(T identity, BinaryOperator accumulator)
U reduce(U identity, BiFunction accumulator, BinaryOperator combiner)
If you don't specify the identity value for 'x', the reduce operator takes the first value from the stream. So 'x' ends up being the letter 'a', as an integer, which is 97. You probably want to change your code to this:
public static int countWords(String s) {
return s.chars().reduce(0, (x, y) -> {
if((char)y == ' ')
return x + 1;
return x;
});
}
While using reduce, you're working with tuples : x being the first char or an accumulator and y the secone char variable.
Here, x always points to a which ASCII value is 97
Pattern#splitAsStream(CharSequence)
You may want to use this method in your case, it does the job just right and you write an easier to maintain code.
public static int countWords(String s) {
return (int)Pattern.compile(" ")
.splitAsStream(s)
.count();
}
Counting spaces: see sprinter's response; performance: see comments to erkfel's response; correct application of reduce: see Andrew Williamson's response.
Now I combined them all to the following:
public static int countWords(String s)
{
int c = s.chars().reduce(0, (x, y) ->
{
if(x < 0)
{
if(Character.isWhitespace(y))
{
x = -x;
}
}
else
{
if(!Character.isWhitespace(y))
{
x = -(x + 1);
}
}
return x;
});
return c < 0 ? -c : c;
}
This counts real words, not the whitespace, in a very efficient way. There is a little trick hid within: I am using negative values to represent the state "within a word" and positive values to represent "within whitespace sequence". I chose this for not having to carry an additional boolean value, saving us from writing an explicit class implementing IntBinaryOperation (additionally, this keeps the lamda expression stateless, still parallelising as talked of in the reduction article would not be possible as this operator is not associative...)).
Edit: As Holger pointed out (I think rightly), this usage is abuse of how recude actually is intended (have several alike values and reduce them to a single one still alike the original ones; example: summating or multiplying a list of numerical values, result still is numerical - or concatenating a list of strings, result still is a string).
So simply iterating over the string seems to be more appropriate:
public static int countWords(String s)
{
int count = 0;
boolean isWord = false;
for(int i = 0; i < s.length(); i++)
{
if(isWord)
{
if(Character.isWhitespace(s.charAt(i)))
{
isWord = false;
}
}
else
{
if(!Character.isWhitespace(s.charAt(i)))
{
++count;
isWord = true;
}
}
return count;
}
I personally like compact variants, although less understandable:
public static int countWords(String s)
{
int count = 0;
boolean isWord = false;
for(int i = 0; i < s.length(); i++)
{
boolean isChange = isWord == Character.isWhitespace(s.charAt(i));
isWord ^= isChange;
count += isWord & isChange ? 1 : 0;
}
return count;
}
Streams? How about:
int wordCount = str.trim().split("\\s+").length();
If you desperately must use streams (not recommended):
int wordCount = Arrays.stream(str.trim().split("\\s+")).count();
I have to solve an exercise, counting all the uppercase chars in a String - recursively - Anyhow I thought I might have found a solution - but it won't work…
Probably you might help me? Thanks!
public static int CountCapitals(String s) {
int counter = 0;
// if (Character.isUpperCase(s.charAt(0)))counter+=1;
if (s.length() == 0)
return counter;
if (s.length() == 1 && s.charAt(0) < 65 && s.charAt(0) > 90)
return 0;
if (s.charAt(0) < 'A' && s.charAt(0) > 'Z') {
return CountCapitals(s.substring(1));
}
if (s.charAt(0) >= 'A' && s.charAt(0) <= 'Z')
counter++;
return CountCapitals(s.substring(1));
}
The problem with your code is the use of counter: each level of invocation has its own counter, initially set to zero. The ++ operator at the bottom has no effect.
You need to compute the result of this invocation based on the result of the previous invocation. Your base case (i.e. s.length() == 0) is fine; the rest of your code needs to change so that it returns whatever CountCapitals(s.substring(1)) when the first letter is non-capital; when the first letter is capital, your function should return 1 + CountCapitals(s.substring(1)).
You need to consider the case when the length of string is 1 and the only character is uppercase (in this case, you should return 1).
Also you need to pass in the counter as a parameter rather than expecting it to "carry over" into other function calls.
This recursion should do just what you want:
public static int countCapitals(String s) {
if (s.length() == 0) return 0;
int cap = Character.isUpperCase(s.charAt(0)) ? 1 : 0;
return countCapitals(s.substring(1)) + cap;
}
If this wasn't a home assignment, you could try an iterative approach which is about 5-10 times faster:
public static int countCapitals(String s) {
int count = 0;
for (int idx = 0; idx < s.length(); idx++) {
if (Character.isUpperCase(s.charAt(idx))) {
count++;
}
}
return count;
}
You don't really need to use a counter variable to keep track of the number of capitals. Instead, you can just the recursive calls, themselves, to keep track of the total:
public static int CountCapitals(String s)
{
if (s.length() == 1)
return (Character.isUpperCase(s.charAt(0)) ? 1 : 0);
else
return CountCapitals(s.substring(1)) +
(Character.isUpperCase(s.charAt(0)) ? 1 : 0);
}
If this is for an assignment and you have to use ASCII values, then fine, but if not, you really should just Character.isUpperCase(char c). In case you're not familiar with the conditional operator, it's defined as follows:
if(someExpression == true)
{
//output 1
}
else
{
//output 0
}
is represented succinctly as:
(someExpression == true) ? 1 : 0
NB:
In your example, counter is set to 0 at the beginning of each method call, so that's why it's not working. If you really want to use a counter, pass it as a parameter to the method instead, and update the parameter with each method call. When you get to the end of the String, simply return the parameter.
You try this
public class HelloWorld{
public static int isUpperCase(String str){
if(str.length()==0) return 0;
boolean check =Character.isUpperCase(str.charAt(0));
if(check){
return isUpperCase(str.substring(1))+1;
}
return isUpperCase(str.substring(1));
}
public static void main(String []args){
String n= "FSAsdsadASdcCa";
System.out.println(isUpperCase("FSAsdsadASdcCa"));
}
}
So im working on java codingbat and this is the question:
Given a string, look for a mirror image (backwards) string at both the beginning and end of the given string.
In other words, zero or more characters at the very begining of the given string, and at the very end of the string in reverse order (possibly overlapping).
For example:
the string "abXYZba" has the mirror end "ab". mirrorEnds("abXYZba") → "ab" mirrorEnds("abca") → "a" mirrorEnds("aba") → "aba" .
My code passed all the test except for the other test, which is not specified. I dont know what's wrong with it.
public String mirrorEnds(String string) {
String input = string, mirror = "";
int length = string.length();
for (int n = 0; n < (length+1) / 2; n++) {
if (input.charAt(n) != input.charAt(length - n - 1)) {
break;
}else if(length%2 == 1 && n == (length - 1)/2){
// System.out.println("length/2 = " );
return input;
}
else {
mirror += input.charAt(n);
}
}
return mirror;
}
You were correct in not needing to go though the entire word, but your logic is more complex than it needs to be, making it harder to find and fix the problem. The root cause of the test failure is in the last return statement. It must return string if the loop completes without breaking. You can fix your code by changing break; to return mirror; and changing the last return mirror; to return input;
The test that is failing is one like this:
mirrorEnds("abba") -> "abba"
A much simpler version of your code can be created like this:
public String mirrorEnds(String string) {
int len = string.length();
for (int i=0; i < len/2; ++i)
if (string.charAt(i) != string.charAt(len - 1 - i))
return string.substring(0, i);
return string;
}
mirrorEnds("abba")?
Anyways, I'm sure you could come up with a better question name than "some weird stuff"...
Since you are dividing n by 2 in your loop termination condition, it will end when halfway through the word. This is enough to tell the word is a palindrome, but not enough to build your output correctly. You have a condition handling palindrome with odd numbers of letter, but not even numbers of letters. I believe the failing test will be of the form "abba", where I believe what you have will return "ab", instead of "abba".
If you change you loop to:
for (int n = 0; n < length; n++) {
I believe it should be doing what you want. This also makes the short circuit case unnecessary, so:
for (int n = 0; n < length; n++) {
if (input.charAt(n) != input.charAt(length - n - 1)) {
break;
}
else {
mirror += input.charAt(n);
}
}
The first test I tried was with the string "abba" which fails. It returns ab, and not abba. As femtoRgon mentioned, you're not going through the entire word, which may some times be necessary. femtoRgon's solution works, as well as taking a slightly different approach to iterating through the word as follows:
public String mirrorEnds(String string) {
boolean matches = true;
StringBuilder mirrorEnd = new StringBuilder();
int index = 0;
while (matches && index < string.length()) {
if (string.charAt(index) == string.charAt(string.length() - index - 1))
mirrorEnd.append(string.charAt(index));
else
matches = false;
index++;
}
return mirrorEnd.toString();
}
public String mirrorEnds(String string) {
String comp="";
for(int i=0; i<string.length(); i++){
if(string.charAt(i)==string.charAt(string.length()-(i+1)))
comp= comp+ string.charAt(i);
else break;
}
return comp;
}