输入格式
第一行将包含序列中的数字集。数 按升序列出。
边界条件
1< = M< = 99999字符串S的长度为5到200.
输出格式
第一行将包含缺失的数字M.
示例输入/输出1
输入:12346789
输出:5
输入/输出2 输入596597598600601602
输出:599
序列中的序列号为596 597 598 599 600 601 602. 599是缺失的数字
我的Java解决方案是:
我已经使用split(("?<=\\G..."))
等将数字分成一个,两个,三个四个和五个数字。并将数字保存到相应的数组中。然后我检查了数组中两个相邻数字之间的任何差异 - 如果它是1,那么它将调用一个函数来找到丢失的数字。
但问题在于:
输入:
999899991000110002
输出
10000
序列是9998 9999 10001 10002.缺失的数字是10000
当可以从4位数转换为5位数时,如何拆分字符串?有没有更好的方法来解决这个问题?
public void test(Scanner in)
{
String n = in.nextLine();
int n1 = n.length();
System.out.println(n1);
if (n1 % 2 == 0)
{
} else {
n = "0" + n;
}
System.out.println(n);
String[] one = n.split("(?<=\\G.)");
String[] two = n.split("(?<=\\G..)");
String[] three = n.split("(?<=\\G...)");
String[] four = n.split("(?<=\\G....)");
String[] five = n.split("(?<=\\G.....)");
int x = one.length;
int y = two.length;
int z = three.length;
int u = four.length;
int v = five.length;
int[] aa1 = new int [x];
int[] aa2 = new int [y];
int[] aa3 = new int [z];
int[] aa4 = new int [u];
int[] aa5 = new int [v];
for (int i = 0; i < x; i++)
{
aa1[i] = Integer.parseInt(one[i]);
}
if (aa1[1] == aa1[3] - 2)
{
findmissing(aa1, x);
}
for (int i = 0; i < y; i++)
{
aa2[i] = Integer.parseInt(two[i]);
}
if (aa2[1] == aa2[3] - 2)
{
findmissing(aa2, y);
}
for (int i = 0; i < z; i++)
{
aa3[i] = Integer.parseInt(three[i]);
}
if (aa3[1] == aa3[3] - 2)
{
findmissing(aa3, z);
}
for (int i = 0; i < u; i++)
{
aa4[i] = Integer.parseInt(four[i]);
}
if (aa4[1] == aa4[3] - 2)
{
findmissing(aa4, u);
}
for (int i = 0; i < v; i++)
{
aa5[i] = Integer.parseInt(five[i]);
}
if (aa5[1] == aa5[3] - 2)
{
findmissing(aa5, v);
}
in.close();
}
public static void findmissing(int[] bb, int value)
{
for (int i = 0; i < value - 1; i++)
{
if (bb[i] == bb[i + 1] - 1)
{
} else {
System.out.println(bb[i + 1] - 1);
}
}
}
答案 0 :(得分:1)
如果(我假设)数字按顺序列出,那么一个非常简单的算法将起作用:
try(toInt(S[1 .. d]), S[d+1 .. |S|])
尝试以S [1 .. d]编码的数字开头的数字序列。如果此序列&#34;起作用&#34;,则输出并停止。上面的主循环在d = 5处停止,因为你给出了M <= 99999的约束,但它可以很容易地使用任意大数,只需让d一直增加到| S |。
第二步(&#34;尝试......&#34;)很简单,因为你已经在这个(候选)序列中有第一个数字x,所以你可以很容易地生成对应于应该出现的数字(即对应于x + 1)并将其与S的余数进行比较。如果对应于x + 1的数字字符串与S的前几个字符不匹配,则尝试对应的数字字符串到x + 2。如果匹配,则设置一个标记,记录x + 1可能是缺失的数字,然后继续。如果x + 1和x + 2不匹配,或者x + 1不匹配并且标志已经设置,我们知道初始值不能正确,所以返回并让主循环尝试下一个更长的时间初始号码:
try(x, S):
x1str = asString(x + 1)
x2str = asString(x + 2)
missing = -1 # Flag value to indicate "not found"
while |S| >= |x1str|:
if S[1 .. |x1str|] = x1str:
Delete first |x1str| characters of S
x = x + 1
x1str = asString(x + 1)
x2str = asString(x + 2)
else if S[1 .. |x2str|] = x2str and missing = -1:
Delete first |x2str| characters of S
missing = x + 1
x = x + 2
x1str = asString(x + 1)
x2str = asString(x + 2)
else
return -1 # Flag value to indicate "invalid sequence"
if |S| > 0 then return -1 # Some gunk was left over
return missing
显然你可以替换&#34;删除第一个...... S&#34;只是在(不变)字符串中使用偏移量的步骤,但我觉得上面的解释更容易。
答案 1 :(得分:1)
这是一个递归的,可运行的解决方案
public class FindGaps {
public static void main(String... args) throws Exception {
System.out.println(gapFinder("12345789"));//6 expected
System.out.println(gapFinder("99101"));//100 expected
System.out.println(gapFinder("124126"));//123 expected
System.out.println("fail expected: " + gapFinder("124125"));
System.out.println("fail expected: " + gapFinder("123456A8"));
System.out.println("fail expected: " + gapFinder("9910010210"));
System.out.println("fail expected: " + gapFinder("10121416"));
}
public static int gapFinder(final String sequence) throws Exception {
for (int digits = 1; digits <= sequence.length() / 2; digits++) {
final Integer currentNumber = Integer.parseInt(sequence.substring(0, digits));
final Integer ret = recursiveGapChecker(currentNumber + 1, sequence.substring(digits));
if (ret != null && ret >= 0) {
return ret;
}
}
return -1;
}
/**
* @return null if the sequence is validated, the missing number if a gap is found, return<0 if the sequence is invalid
*/
private static Integer recursiveGapChecker(final Integer nextNumber, final String remainder) {
final String numAsString = nextNumber.toString();
final int numLength = numAsString.length();
final Integer numPlus1 = nextNumber + 1;
final String numPlus1AsString = numPlus1.toString();
final int numPlus1Length = numPlus1AsString.length();
if (remainder.isEmpty()) {
return null;//cleanly parsed the remainer
} else if (remainder.length() < numLength) {
return -1;//invalid length
} else if (remainder.startsWith(numAsString)) {
return recursiveGapChecker(nextNumber + 1, remainder.substring(numLength));
} else if (remainder.startsWith(numPlus1AsString)) {
Integer ret = recursiveGapChecker(numPlus1 + 1, remainder.substring(numPlus1Length));
if (ret == null) {
return nextNumber;//found it!
} else if (ret < 0) {
return -1;//problem parsing the rest of the string
} else {
return -2;//found more than one gap
}
} else {
return -1;//the remainder doesn't match the given number
}
}
}
答案 2 :(得分:0)
如果你已经知道了第一个数字,那么这应该有用。确定第一个数字可能会很棘手。
public class SeqTest
{
public static void main(String[] args)
{
new SeqTest().test("999899991000110002", 9998);
System.exit(0);
}
public void test(String line, int nextExpectedNumber)
{
String remainingLine = line;
boolean expected = true;
Integer nextNumber = nextExpectedNumber;
while (expected)
{
String expectedString = nextNumber.toString();
if (!remainingLine.startsWith(expectedString))
{
expected = false;
System.out.println("Missing " + expectedString + " from " + remainingLine);
} else {
// prune remainingLine
remainingLine = remainingLine.substring(expectedString.length());
}
nextNumber = this.nextInSequence(nextNumber);
}
return;
}
public Integer nextInSequence(int current)
{
return ++current;
}
}
答案 3 :(得分:0)
除了解决OP提出的问题之外,还必须解决另外两个问题。
无论如何,这是我针对我的代码运行的测试用例。第一行是数字字符串。第二行是字符串中的数字数组。第三行是缺失的数字。
1234678910
[1, 2, 3, 4, 6, 7, 8, 9, 10]
5
26272829313233
[26, 27, 28, 29, 31, 32, 33]
30
9293949596979899101
[92, 93, 94, 95, 96, 97, 98, 99, 101]
100
99101102103104105106107108109110111112
[99, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112]
100
596597598600601602
[596, 597, 598, 600, 601, 602]
599
989999009901990299049905
[9899, 9900, 9901, 9902, 9904, 9905]
9903
98999901990299039904990599069907
[9899, 9901, 9902, 9903, 9904, 9905, 9906, 9907]
9900
9998999910000100011000210004
[9998, 9999, 10000, 10001, 10002, 10004]
10003
从此代码中获取的要点是尝试所有可以想到的边缘情况。除非我编写代码,否则我不会想到9899,9900序列。
package com.ggl.testing;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class MissingNumber implements Runnable {
private String numberString;
public static void main(String[] args) {
MissingNumber missingNumber = new MissingNumber();
missingNumber.setNumberString("1234678910");
missingNumber.run();
missingNumber.setNumberString("26272829313233");
missingNumber.run();
missingNumber.setNumberString("9293949596979899101");
missingNumber.run();
missingNumber.setNumberString("99101102103104105106107108109110111112");
missingNumber.run();
missingNumber.setNumberString("596597598600601602");
missingNumber.run();
missingNumber.setNumberString("989999009901990299049905");
missingNumber.run();
missingNumber.setNumberString("98999901990299039904990599069907");
missingNumber.run();
missingNumber.setNumberString("9998999910000100011000210004");
missingNumber.run();
}
public void setNumberString(String numberString) {
this.numberString = numberString;
}
@Override
public void run() {
System.out.println(numberString);
Integer[] numbers = getNumbers(numberString);
System.out.println(Arrays.toString(numbers));
int missingNumber = findMissingNumber(numbers);
System.out.println(missingNumber + "\n");
}
private Integer[] getNumbers(String numberString) {
List<Integer> numbers = new ArrayList<>();
int index1 = 0;
int index2 = 1;
int length = 1;
boolean isAdjacent = false;
while (!isAdjacent) {
Integer test1 = getSubstring(numberString, index1, length);
Integer test2 = getSubstring(numberString, index2, length);
Integer test3 = getSubstring(numberString, index2, length + 1);
if (isValidDifference(test2, test1)) {
numbers.add(test1);
numbers.add(test2);
try {
getRemainingNumbers(numberString, numbers, index2, length,
test2);
isAdjacent = true;
} catch (NumberFormatException e) {
numbers.clear();
length++;
index1 = 0;
index2 = index1 + length;
}
} else if (isValidDifference(test3, test1)) {
numbers.add(test1);
numbers.add(test3);
length++;
try {
getRemainingNumbers(numberString, numbers, index2, length,
test3);
isAdjacent = true;
} catch (NumberFormatException e) {
numbers.clear();
length++;
index1 = 0;
index2 = index1 + length;
}
} else {
length++;
index2 = index1 + length;
}
}
return numbers.toArray(new Integer[numbers.size()]);
}
private void getRemainingNumbers(String numberString,
List<Integer> numbers, int index2, int length, Integer previousTest)
throws NumberFormatException {
int index = index2 + length;
while (index <= (numberString.length() - length)) {
Integer test = getSubstring(numberString, index, length);
if (isValidDifference(test, previousTest)) {
numbers.add(test);
previousTest = test;
index += length;
} else {
length++;
}
}
}
private Integer getSubstring(String string, int index, int length)
throws NumberFormatException {
return Integer.valueOf(string.substring(index, index + length));
}
private boolean isValidDifference(int number2, int number1) {
int diff = number2 - number1;
return (diff == 1 || diff == 2);
}
private int findMissingNumber(Integer[] numbers) {
int lastNumber = numbers[0];
for (int i = 1; i < numbers.length; i++) {
int diff = numbers[i] - lastNumber;
if (diff == 2) {
return numbers[i] - 1;
}
lastNumber = numbers[i];
}
return Integer.MIN_VALUE;
}
}
答案 4 :(得分:0)
我认为您可以改进此代码,但请尝试:
public static void main(String[] args) {
String pattern = "(\\d{%s})(\\d{0,%s})";
String toVerify = "9979989991000100110021004";
String toVerifyCopy = toVerify;
List<Integer> items = new LinkedList<>();
Integer found = null;
for (int i = 1; i < toVerifyCopy.length(); i++) {
int first = 0;
Integer second = 0;
int secondSize = i;
boolean isSize = false;
for (int j = 1; j < i + 2; j++) {
Pattern patron = Pattern.compile(String.format(pattern, i, j));
Matcher matcher = patron.matcher(toVerifyCopy);
if (matcher.find()) {
first = Integer.parseInt(matcher.group(1));
second = Integer.parseInt(matcher.group(2));
if (second == first + 1) {
secondSize = j;
isSize = true;
j++;
} else if (second == first + 2) {
found = first + 1;
secondSize = j;
isSize = true;
j++;
} else {
isSize = false;
}
}
}
if (isSize) {
toVerifyCopy = toVerifyCopy.substring(i);
i = i - 1;
if (items.size() < 2 ||
toVerifyCopy.length() == i + secondSize) {
items.add(first);
}
items.add(second);
} else {
if (items.size() > 0) {
if (first == items.get(items.size() - 1)) {
items.clear();
toVerifyCopy = toVerify;
}
}
}
}
for (Integer item : items) {
System.out.println(item);
}
if (found != null) {
System.out.println("Found: " + found);
}
}
答案 5 :(得分:0)
for a sequence, (3, 4, 6, 7)
or (13, 14, 16, 17)
or (113, 114, 116, 117)
你总是以last-first == sequence.size()//结束,即7-3 = 4
这样,很容易检测到正确的数字长度(至少减少列表数量以便进行显着检查)。
为了提高性能,您可以检查,如果String.length可以被数字长度整除,否则会出现陷阱:
1230124如果您只选择前3个和后3个字符,则测试数字长度为3.
import java.util.*;
public class NumberGap {
static private boolean laengeFits (String numbers, int len, int start, int stop) {
String front = numbers.substring (start, len);
String back = numbers.substring (stop - len, stop);
// System.out.printf ("front - back = %s %s\n", front, back);
int first = Integer.parseInt (front);
int last = Integer.parseInt (back);
return (last - first == numbers.length () / len);
}
static private boolean isCandidate (String numbers, int len) {
return (numbers.length() % len == 0 && laengeFits (numbers, len, 0, numbers.length ()));
}
static List <Integer> string2ints (String snum, int i) {
List <Integer> vals = new ArrayList<> ();
for (int n = 0; n < snum.length (); n+= i){
String s = snum.substring (n, n+i);
vals.add (Integer.parseInt (s));
}
return vals;
}
static private void findGap (String numbers) {
System.out.printf ("\nSearching for: %s \n", numbers);
for (int i = 1; i < 6; ++i) {
if (isCandidate (numbers, i)) {
List <Integer> vals = string2ints (numbers, i);
// System.out.printf ("\telems: %d :\n", vals.size ());
List <Integer> res = new ArrayList<> ();
for (int j = 1; j < vals.size (); ++j) {
if (vals.get(j) != vals.get(j-1) + 1) {
res.add (vals.get(j-1) + 1);
if (res.size () > 1) {
System.out.printf ("Error multiple gaps: %d %d\n", res.get (0), res.get(1));
break;
}
}
}
if (res.size() == 1) {
System.out.printf (" * * * Gap: %d * * *\n", res.get (0));
continue;
}
}
}
}
public static void main(String[] args) {
findGap ("012346789");
findGap ("1234678910");
findGap ("26272829313233");
findGap ("26272829313333");
findGap ("9293949596979899101");
findGap ("99101102103104105106107108109110111112");
findGap ("596597598600601602");
findGap ("989999009901990299049905");
findGap ("98999901990299039904990599069907");
findGap ("9998999910000100011000210004");
}
}
我首先写了一个Scala解决方案,一个班轮,承认了很长的路线:
(1 to 5).map (i => {s.sliding (i, i)}.map (_.toInt).toVector).filter (v => (v(v.size - 1) - v(0) == v.size)).flatten .sliding (2, 1).filter {l => l(0) != l(1)-1}.map {l => l(1) -1}.mkString (":")
或更好的可读性:
(1 to 5).map (i => {s.sliding (i, i)}.
map (_.toInt).toVector).
filter (v => (v(v.size - 1) - v(0) == v.size)).
flatten.
sliding (2, 1).
filter {l => l(0) != l(1)-1}.
map {l => l(1) -1}.mkString (":")
使用s作为要解析的String。集合函数的集合更丰富,没有那么麻烦,从Array转换为List或Vector,因为这里只定义了一个方便的函数,另一个只在那里定义。在幕后流畅地从int转换为Integer。