I had a go at writing this bit of java code which allows me to add and subtract (large) numbers which are represented using a String rather than a numeric datatype. This allows me to do basic calculations on numbers much bigger than the numeric data types can handle.
It is a bit rough and ready, I don't perform any checks on the input strings at all for instance, but for the constraints that I am using the code works fine.
I am not that familiar with java library functions (is there something instead of Character#getNumericValue that works better?) and I was wondering if there is any scope for improving the execution speed. I guess when the input numbers differ considerably in length, using the '0's to keep the loop running isn't very efficient. Perhaps I am not using a very good algorithm to do this at all. Any pointers would be welcome.
public static String addBig(String a, String b)
{
// no checks or exception handling at all ...
String result = "";
int carry = 0;
int a_int, b_int, res_int;
for(int current = 1; ; current++)
{
if(current > a.length() && current > b.length())
{
if(carry == 1)
result = "1" + result;
break;
}
a_int = a.length() - current < 0 ? 0
: Character.getNumericValue(a.charAt(a.length() - current));
b_int = b.length() - current < 0 ? 0
: Character.getNumericValue(b.charAt(b.length() - current));
res_int = a_int + b_int + carry;
if(res_int > 9)
{
res_int -= 10;
carry = 1;
}
else
carry = 0;
result = Integer.toString(res_int) + result;
}
return result;
}
public static String subtractBig(String a, String b)
{
// no checks or exception handling at all, a is expected to be bigger than b
String result = "";
int borrow = 0;
int a_int, b_int, res_int;
for(int current = 1; current <= a.length(); current++)
{
// subtract the digits
a_int = Character.getNumericValue(a.charAt(a.length() - current));
b_int = b.length() - current < 0 ? 0
: Character.getNumericValue(b.charAt(b.length()-current));
res_int = (a_int-borrow)-b_int;
if(res_int < 0)
{
res_int += 10;
borrow = 1;
}
else
borrow = 0;
result = Integer.toString(res_int) + result;
}
// tidy zeros
while(result.length() > 1 && result.charAt(0) == '0')
result = result.substring(1);
return result;
}
Related
I Find longest sequence of zeros in binary representation of an integer but result incorrect on app.codility.com with n = 6 and n =328
https://imgur.com/rzFsjaY
public int solution(int N) {
Integer result = 1;
StringBuilder modNumber = new StringBuilder();
while (result > 0) {
result = n / 2;
modNumber.append(n % 2 + "");
n = result;
}
int length = modNumber.length();
String modString = modNumber.toString();
Integer binaryGap = 0;
List<Integer> lstResult = new ArrayList<>();
Boolean isBinaryGap = false;
if (modString.charAt(0) == '0') {
binaryGap = 0;
} else {
for (int i = 1; i < length; i++) {
char c = modString.charAt(i);
if (c == '0') {
binaryGap += 1;
isBinaryGap = true;
} else {
isBinaryGap = false;
}
if(!isBinaryGap) {
lstResult.add(binaryGap);
binaryGap = 0;
}
}
}
int max=0;
if(!lstResult.isEmpty()) {
max = lstResult.stream().collect(Collectors.summarizingInt(Integer::intValue)).getMax();
}
return max;
}
The problem is this part:
if (modString.charAt(0) == '0') {
binaryGap = 0;
} else {
I suspect your intention is to handle the case of the input being zero (so why not do that right off the bat, using the original value of N?), but you get many false positives because your technique for forming the string places the bits in order from least-significant to most-significant. The least-significant bit is zero for every even number, and you therefore report a gap of 0 for all of them, but the only even number for which that's the correct result is 0.
I'm sure that with that information you could fix your code to produce the correct results, but the problem would not even have arisen if you had chosen a simpler approach. For example, how about scanning the binary representation just once, keeping track of the current and maximum gap lengths as you go? You already perform the needed scan, but instead of just computing the result directly, you go through all that mess of building and then analyzing a string representation. Simpler code leaves less room for bugs, and when they arise, they are usually easier to spot.
I'm trying to solve the following problem. Given an integer, n, list all n-digits numbers such that each number does not have repeating digits.
For example, if n is 4, then the output is as follows:
0123
0124
0125
...
9875
9876
Total number of 4-digit numbers is 5040
My present approach is by brute-force. I can generate all n-digit numbers, then, using a Set, list all numbers with no repeating digits. However, I'm pretty sure there is a faster, better and more elegant way of doing this.
I'm programming in Java, but I can read source code in C.
Thanks
Mathematically, you have 10 options for the first number, 9 for the second, 8 for the 3rd, and 7 for the 4th. So, 10 * 9 * 8 * 7 = 5040.
Programmatically, you can generate these with some combinations logic. Using a functional approach usually keeps code cleaner; meaning build up a new string recursively as opposed to trying to use a StringBuilder or array to keep modifying your existing string.
Example Code
The following code will generate the permutations, without reusing digits, without any extra set or map/etc.
public class LockerNumberNoRepeats {
public static void main(String[] args) {
System.out.println("Total combinations = " + permutations(4));
}
public static int permutations(int targetLength) {
return permutations("", "0123456789", targetLength);
}
private static int permutations(String c, String r, int targetLength) {
if (c.length() == targetLength) {
System.out.println(c);
return 1;
}
int sum = 0;
for (int i = 0; i < r.length(); ++i) {
sum += permutations(c + r.charAt(i), r.substring(0,i) + r.substring(i + 1), targetLength);
}
return sum;
}
}
Output:
...
9875
9876
Total combinations = 5040
Explanation
Pulling this from a comment by #Rick as it was very well said and helps to clarify the solution.
So to explain what is happening here - it's recursing a function which takes three parameters: a list of digits we've already used (the string we're building - c), a list of digits we haven't used yet (the string r) and the target depth or length. Then when a digit is used, it is added to c and removed from r for subsequent recursive calls, so you don't need to check if it is already used, because you only pass in those which haven't already been used.
it's easy to find a formula. i.e.
if n=1 there are 10 variants.
if n=2 there are 9*10 variants.
if n=3 there are 8*9*10 variants.
if n=4 there are 7*8*9*10 variants.
Note the symmetry here:
0123
0124
...
9875
9876
9876 = 9999 - 123
9875 = 9999 - 124
So for starters you can chop the work in half.
It's possible that you might be able to find a regex which covers scenarios such that if a digit occurs twice in the same string then it matches/fails.
Whether the regex will be faster or not, who knows?
Specifically for four digits you could have nested For loops:
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
if (j != i) {
for (int k = 0; k < 10; k++) {
if ((k != j) && (k != i)) {
for (int m = 0; m < 10; m++) {
if ((m != k) && (m != j) && (m != i)) {
someStringCollection.add((((("" + i) + j) + k) + m));
(etc)
Alternatively, for a more generalised solution, this is a good example of the handy-dandy nature of recursion. E.g. you have a function which takes the list of previous digits, and required depth, and if the number of required digits is less than the depth just have a loop of ten iterations (through each value for the digit you're adding), if the digit doesn't exist in the list already then add it to the list and recurse. If you're at the correct depth just concatenate all the digits in the list and add it to the collection of valid strings you have.
Backtracking method is also a brute-force method.
private static int pickAndSet(byte[] used, int last) {
if (last >= 0) used[last] = 0;
int start = (last < 0) ? 0 : last + 1;
for (int i = start; i < used.length; i++) {
if (used[i] == 0) {
used[i] = 1;
return i;
}
}
return -1;
}
public static int get_series(int n) {
if (n < 1 || n > 10) return 0;
byte[] used = new byte[10];
int[] result = new int[n];
char[] output = new char[n];
int idx = 0;
boolean dirForward = true;
int count = 0;
while (true) {
result[idx] = pickAndSet(used, dirForward ? -1 : result[idx]);
if (result[idx] < 0) { //fail, should rewind.
if (idx == 0) break; //the zero index rewind failed, think all over.
dirForward = false;
idx --;
continue;
} else {//forward.
dirForward = true;
}
idx ++;
if (n == idx) {
for (int k = 0; k < result.length; k++) output[k] = (char)('0' + result[k]);
System.out.println(output);
count ++;
dirForward = false;
idx --;
}
}
return count;
}
In an interview I had, I was asked to write a program that prints to the screen the numbers 1,2,3,4,5....until 99999999999999.....?(the last number to print is the digit 9 million times)
You are not allowed to use Big-Integer or any other similar object.
The hint I got is to use modulo and work with strings, I tried to think about it but haven't figured it out.
Thanks in advance
You need an array to store the number, and perform operations on the array.
Here's an example
public class BigNumberTest2 {
public static void main(String[] args) {
/*Array with the digits of the number. 0th index stores the most significant digit*/
//int[] num = new int[1000000];
//Can have a million digits, length is 1 + needed to avoid overflow
int[] num = {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
int base = 10;
int step = 1;
String endNum = "100000000000000000000000000000000000000000000000000020";//Can have a million digits
while(true) {
//Increment by step
for(int carry = step, i = num.length - 1; carry != 0 && i >= 0; i--) {
int newDigit = num[i] + carry;
num[i] = newDigit % base;
carry = newDigit / base;
}
//Find the position of most significant digit
int mostSignificantDigitIndex = 0;
while(num[mostSignificantDigitIndex] == 0) {/*No need to check if firstNonZero < num.length, as start num >=0 */
mostSignificantDigitIndex++;
}
StringBuilder strNum = new StringBuilder();
//Concatenate to get actual string
for(int i = mostSignificantDigitIndex; i < num.length; i++) {
strNum.append(num[i]);
}
System.out.println(strNum);
//Check if number current number is greater or equal to endNum
if(strNum.length() > endNum.length() || (strNum.length() == endNum.length() && strNum.toString().compareTo(endNum) >= 0)) {
break;
}
}
}
}
Output
1000000000000000000000000000000000000000000000000000001
1000000000000000000000000000000000000000000000000000002
1000000000000000000000000000000000000000000000000000003
1000000000000000000000000000000000000000000000000000004
1000000000000000000000000000000000000000000000000000005
1000000000000000000000000000000000000000000000000000006
1000000000000000000000000000000000000000000000000000007
1000000000000000000000000000000000000000000000000000008
1000000000000000000000000000000000000000000000000000009
1000000000000000000000000000000000000000000000000000010
1000000000000000000000000000000000000000000000000000011
1000000000000000000000000000000000000000000000000000012
1000000000000000000000000000000000000000000000000000013
1000000000000000000000000000000000000000000000000000014
1000000000000000000000000000000000000000000000000000015
1000000000000000000000000000000000000000000000000000016
1000000000000000000000000000000000000000000000000000017
1000000000000000000000000000000000000000000000000000018
1000000000000000000000000000000000000000000000000000019
1000000000000000000000000000000000000000000000000000020
Something like this:
This is a PHP, but you could transform it to java easy...
Recursion with increasing number through string.
function nextNum($num="", $step=1, $end="999999999999999999") {
$string = "";
$saving = 0;
for($i=strlen($num)-1; $i>=0; $i--) {
$calc = intval(intval($num[$i]) + $saving);
if ($i==(strlen($num)-1)) $calc = $calc + $step;
if (strlen($calc)==2) {
$calc = $calc."";
$saving = intval($calc[0]);
$calc = intval($calc[1]);
}
else {
$calc = intval($calc);
$saving = 0;
}
$string = $calc . $string;
}
if ($saving!=0) $string = $saving.$string;
echo $string." ";
if ($end == $string || strlen($end)<strlen($string)) { return; }
else return nextNum($string, $step, $end);
}
nextNum("0", 1, "999999999999999999");
I didn't test it... but it should work..
My assignment is to create a recursive method makeDecimal that when passed a number (that is represented by a String) and its base, converts the number to base 10. You will need to use the method Integer.parseInt(str). (Hint: use substrings.) This method takes a String and returns the integer form of it.
For example, Integer.parseInt("21"); will return the int 21.
Here are some examples of how makeDecimal works:
makeDecimal("11", 2) will return 3.
makeDecimal("100", 4) will return 16.
Here was my attempt at it:
public static double makeDecimal(String number, int base){
int len = number.length();
double f = 0;
if(len <= 0)
return 0;
else{
makeDecimal(number,base);
double temp = Integer.parseInt(number.substring(len - 1, len + 1));
f = f + temp * Math.pow(3, len-1);
}
len--;
return f;
}
However, I get an "overflow error", and I don't know if it even is written correctly.
You are recursing with exactly the same arguments that were passed in. As a result, the call will itself recurse the same way, until the stack overflows. That's not how recursion is supposed to work. Instead, you need to figure out how to do one piece of the problem in the current call and then recurse to do a smaller problem.
In your code, it's not even clear what logic you are using. (What's the point of computing 3len-1?) Try this instead:
If the input string has length 0, the answer is 0 (that part you got right)
Otherwise, take the last digit and parse it in the current base. Then the answer is that value plus base times the value of everything up to but not including the last digit of the input. (Hint: this is a good place to use recursion.)
You should be able to translate that description into the appropriate method calls and use of substring().
Oh, one other thing: there's no reason to be using double values here. Just stick with int variables throughout. You won't be needing Math.pow().
Here is simplest solution using recursion, substring and Integer.parseInt:
public int makeDecimal(String value, int base) {
// exit from recursion
if (value.length() < 1)
return 0;
//parsing last character of string
int charValue = Integer.parseInt(value.substring(value.length() - 1), base);
//calling recursion for string without last character
return makeDecimal(value.substring(0, value.length() - 1), base) * base + charValue;
}
Here's my solution after writing the prototype in Python (if you are interested, I can also include the Python source code):
import java.util.HashMap;
import java.util.Map;
public class MakeDecimal {
public static final Map<Character, Integer> alphabet = buildAlphabetTable();
public static void main(String[] args) {
// System.out.println(alphabet);
System.out.println(makeDecimal("af10bb1", 16));
}
// pos refers to the position of the character in the string.
// For example, if you have the following binary string 100
// then 1 at the left is at position 2,
// the 0 in the middle is at position 1,
// and the right most 0 is at position 0
// (you start counting from the right side).
// In general, you would convert that string in the following way:
// 2^2 * 1 + 2^1 * 0 + 2^0 * 0 = 4
// If the base was n, then you would have
// first * n^{pos + "length of string - 1"} + ... + penultimate * n^{pos + 1} + last * n^{pos}
// Note that pos starts from 0.
private static int makeDecimal(String s, int base, int pos) {
if (s.length() == 0) {
return 0;
} else {
int last = (int) Math.pow(base, pos) * alphabet.get(s.charAt(s.length() - 1));
return makeDecimal(s.substring(0, s.length() - 1), base, pos + 1) + last;
}
}
public static int makeDecimal(String s, int base) {
if (s.length() == 0) {
return 0;
}
if (base < 2 || base > 36) {
throw new IllegalArgumentException("not base >= 2 and base <= 36");
}
return makeDecimal(s.toLowerCase(), base, 0);
}
// Creates a table that maps characters to their decimal value
// the characters can be also '0' or '2' (or any other character number)
// or they can be a character of the English alphabet
private static Map<Character, Integer> buildAlphabetTable() {
Map<Character, Integer> a = new HashMap<>(36);
int i = 0;
for (char c = '0'; c <= '9'; c++, i++) {
a.put(c, i);
}
for (char c = 'a'; c <= 'z'; c++, i++) {
a.put(c, i);
}
return a;
}
}
My solution is based on the following post, which you should definitely read to refresh your ideas on how to convert between bases.
http://www.purplemath.com/modules/numbbase.htm
It does not accept bases that are smaller than 2 or greater than 36. It handles also when you pass English characters in upper case.
Edit: At first I've misted that recursion is obligated for this solution so my original answer without it could me four below.
Here is solution with recursion and without substring and Math.pow:
public double makeDecimal(String value, int base) {
makeDecimal(value, base, value.length() - 1);
}
public double makeDecimal(String value, int base, int index) {
double result = 0;
if (index < 0)
return result;
double charValue = 0;
char currentChar = values.get(Character.toUpperCase(value.charAt(index));
if (currentChar >= 0 && currentChar <= '9') {
charValue = currentChar - '0';
} else if (currentChar >= 'A' && currentChar <= 'Z') {
charValue = currentChar - 'A';
} else {
throw new InvalidValueException("Unsupported character '" + currentChar + "'.");
}
if (charValue >= base) {
throw new InvalidValueException("Wrong character '" + currentChar + "' for base '" base + "'.");
}
return makeDecimal(value, base, index - 1)) * base + charValue;
}
Original Answer: Something like this should work for any base starting from 2 till 36:
private Map<Character, Integer> getCharValues(int base)
{
Map<Character, Integer> values = new HashMap<Character, Integer>();
for (int i = 0; i < base; i++){
if (i < 10) {
values.put('0' + i, i);
} else if (i < 36) {
values.put('A' + i - 10, i);
} else {
throw new InvalidValueException("Base '" + base + "' not supported");
}
}
return values;
}
public double makeDecimal(String value, int base)
{
Map<Character, Integer> charValues = getCharValues(base);
double result = 0;
for (int i = 0; i < value.length(); i++){
result = result * base + charValues.get(Character.toUpperCase(Character.toUpperCase(value.charAt(i))));
}
return result;
}
If you need base more then 36 you can extend char set in method getCharValues. Also it will be a good idea do not create HasMap every time but just store it for maximum base and throw exception if char value exceed given base.
I am trying to figure out how to count all numbers between two ints(a and b), where all of the digits are divisible with another int(k) and 0 counts as divisible.Here is what I've made so far, but it is looping forever.
for (int i = a; i<=b; i++){
while (i < 10) {
digit = i % 10;
if(digit % k == 0 || digit == 0){
count ++;
}
i = i / 10;
}
}
Also I was thinking about comparing if all of the digits were divisible by counting them and comparing with number of digits int length = (int)Math.Log10(Math.Abs(number)) + 1;
Any help would be appreciated. Thank you!
Once you get in to your while block you're never going to get out of it. The while condition is when i less than 10. You're dividing i by 10 at the end of the whole block. i will never have a chance of getting above 10.
Try this one
public class Calculator {
public static void main(String[] args) {
int a = 2;
int b = 150;
int k = 3;
int count = 0;
for (int i = a; i <= b; i++) {
boolean isDivisible = true;
int num = i;
while (num != 0) {
int digit = num % 10;
if (digit % k != 0) {
isDivisible = false;
break;
}
num /= 10;
}
if (isDivisible) {
count++;
System.out.println(i+" is one such number.");
}
}
System.out.println("Total " + count + " numbers are divisible by " + k);
}
}
Ok, so there are quite a few things going on here, so we'll take this a piece at a time.
for (int i = a; i <= b; i++){
// This line is part of the biggest problem. This will cause the
// loop to skip entirely when you start with a >= 10. I'm assuming
// this is not the case, as you are seeing an infinite loop - which
// will happen when a < 10, for reasons I'll show below.
while (i < 10) {
digit = i % 10;
if(digit % k == 0 || digit == 0){
count ++;
// A missing line here will cause you to get incorrect
// results. You don't terminate the loop, so what you are
// actually counting is every digit that is divisible by k
// in every number between a and b.
}
// This is the other part of the biggest problem. This line
// causes the infinite loop because you are modifying the
// variable you are using as the loop counter. Mutable state is
// tricky like that.
i = i / 10;
}
}
It's possible to re-write this with minimal changes, but there are some improvements you can make that will provide a more readable result. This code is untested, but does compile, and should get you most of the way there.
// Extracting this out into a function is often a good idea.
private int countOfNumbersWithAllDigitsDivisibleByN(final int modBy, final int start, final int end) {
int count = 0;
// I prefer += to ++, as each statement should do only one thing,
// it's easier to reason about
for (int i = start; i <= end; i += 1) {
// Pulling this into a separate function prevents leaking
// state, which was the bulk of the issue in the original.
// Ternary if adds 1 or 0, depending on the result of the
// method call. When the methods are named sensibly, I find
// this can be more readable than a regular if construct.
count += ifAllDigitsDivisibleByN(modBy, i) ? 1 : 0;
}
return count;
}
private boolean ifAllDigitsDivisibleByN(final int modBy, final int i) {
// For smaller numbers, this won't make much of a difference, but
// in principle, there's no real reason to check every instance of
// a particular digit.
for(Integer digit : uniqueDigitsInN(i)) {
if ( !isDigitDivisibleBy(modBy, digit) ) {
return false;
}
}
return true;
}
// The switch to Integer is to avoid Java's auto-boxing, which
// can get expensive inside of a tight loop.
private boolean isDigitDivisibleBy(final Integer modBy, final Integer digit) {
// Always include parens to group sub-expressions, forgetting the
// precedence rules between && and || is a good way to introduce
// bugs.
return digit == 0 || (digit % modBy == 0);
}
private Set<Integer> uniqueDigitsInN(final int number) {
// Sets are an easy and efficient way to cull duplicates.
Set<Integer> digitsInN = new HashSet<>();
for (int n = number; n != 0; n /= 10) {
digitsInN.add(n % 10);
}
return digitsInN;
}