9.14 去哪儿笔试(开发)(含个人解题思路代码)
如果有更好的思路欢迎在评论区讨论。 共勉~
第一题:如果一个数可以整除3,那么它每位数的和一定是3的倍数。
我们记录下来0-9每个数出现了多少次,并记录一下这些数的和 sum。
计算 sum % 3
0: 符合要求,直接输出就好。
1: 需要删除一个 %3 = 1 的数,如果没有就删除两个 %3 = 2的数。
2: 同1。
public String solution1(int[] d) {
int[] cnt = new int[10];
int[] modulo = new int[3];
int sum = 0;
for (int t : d) {
++cnt[t];
++modulo[t % 3];
sum += t;
}
int l; // %3 == l的数 删除 r 个
int r;
int mod = sum % 3;
if (mod == 0) {
l = r = 0;
} else {
if (modulo[mod] >= 1) {
l = mod;
r = 1;
} else {
l = 2 * mod % 3;
r = 2;
}
}
StringBuffer buffer = new StringBuffer();
for (int i = 0; i < 10; i++) {
char ch = (char) (i + '0');
for (int j = 0; j < cnt[i]; ++j) {
if (r > 0 && i % 3 == l) {
--r;
} else {
buffer.append(ch);
}
}
}
// 0000 的情况
if (buffer.length() > 0 && buffer.charAt(buffer.length() - 1) == '0') {
buffer = new StringBuffer("0");
}
return buffer.reverse().toString();
} 第二题:记录下来所有正数的和 sum。
负数扔到优先队列中(从大到小)从中依次取数,定义一个变量t 记录要选的所有负数的和。
那么选择一个负数带来的收益就是 sum + t(t是负的)。
只需判断 abs(t) 是否小于等于 sum 。
更好的思路:
一个sum记录选择的数的和。 每选一个数,带来的收益就是sum。
//笔试时写的
public int solution2(int[] arr) {
int sum = 0;
PriorityQueue<Integer> que = new PriorityQueue<>();
PriorityQueue<Integer> fuQ = new PriorityQueue<>((o1, o2) -> o2 - o1);
for (int t : arr) {
if (t >= 0) {
sum += t;
que.add(t);
} else {
fuQ.add(t);
}
}
int k = 1;
int ans = 0;
int t = 0;
int last = 0;
while (!fuQ.isEmpty()) {
t += fuQ.remove();
if (-t <= sum) {
ans += t;
k++;
}
}
while (!que.isEmpty()) {
t = que.remove();
ans += t * k;
k++;
}
return ans;
}
// 更好的思路
public static int solution2_2(int[] arr) {
Arrays.sort(arr);
int ans = 0;
int sum = 0;
for(int i = arr.length - 1; i >= 0 ;i--){
sum+=arr[i];
if(sum > 0) ans += sum;
else break;
}
return ans;
} 第三题:我的算法最差应该是 O(n2) 的时间复杂度。
我发现一个规律,半回文串都是 1232123 、 1234321234 这种由两个回文串组成。第一个: 12321 和 32123 。第二个1234321、4321234。
但是长度为4的半回文串不符合上述规律,需单独处理。 if(s[i] == s[i+2] && s[i+1] == s[i+3])
然后利用马拉车算法 (O(n)) 求出 每个下标为中心 的回文串长度。去判断上述规律。 len[i] == len[j] && j - i == len[i]/2 - 2; len[i] 表示以 s[i] 为中心的回文串的长度。
判断最差是O(n2)的算法。
public int solution3(String str) {
if (str == null || str.length() < 4) return 0;
StringBuilder sb = new StringBuilder();
sb.append("$");
char[] s = str.toCharArray();
int ans = 0;
for (int i = 0; i < str.length(); i++) {
if (i + 3 < str.length())
if (s[i] == s[i + 2] && s[i + 1] == s[i + 3]) ans++;
sb.append('#');
sb.append(s[i]);
}
sb.append("#@");
int n = sb.length();
int[] p = new int[n];
int id = 0, mx = 0;
int idex = 0;
for (int j = 1; j < n - 1; j++) {
p[j] = mx > j ? Math.min(p[2 * id - j], mx - j) : 1;
while (sb.charAt(j + p[j]) == sb.charAt(j - p[j])) {
p[j]++;
}
if (mx < p[j] + j) {
mx = p[j] + j;
id = j;
}
}
for (int j = 2; j < n - 1; j += 2) {
if (p[j] >= 6) {
int tem = p[j];
for (int i = j + p[j] - 2; i >= j + 4; i -= 2) {
if (p[i] >= tem) ans++;
tem-=2;
}
}
}
return ans;
} 