2019届vivo秋招笔试题【字符串排序】【链表奇数位正序偶数位逆序】【最长回文子串】

字符串排序

1.题目描述

请对组字符串进行排序,字符串由大小写字母和数字组成,需要满足以下比较规则

  • 1、长度不同时,长度较短在排前面
  • 2、长度相同时,按照字典顺序排列(AaBb-Zz, 0-9顺序),即大写字母在小写字母前,数字排在字母后,要求时间复杂度为O(nlogn)。

比如:
abc Abc 123 1bc CBD abed a
排序后结果为:
a 1 Abc abc CBD 1bc 123 abcd

2.解题思路

ASCII码:0-9(对应数值48-59);A-Z(对应数值65-90);a-z(对应数值97-122);
排序为(AaBb-Zz, 0-9顺序),不符合常规字典排序,故这里我重新定义了ASCII码,因为A和a的ascii码相差32,这里定义A的ascii码为32,依次排序为
| 字符 | 重新定义的ASCII码 | 字符 | 重新定义的ASCII码 | 字符 | 重新定义的ASCII码 |
| — | — | — | — | — | — |
| A | 32 | L | 54 | v | 75 |
| a | 33 | l | 55 | W | 76 |
| B | 34 | M | 56 | w | 77 |
| b | 35 | m | 57 | X | 78 |
| C | 36 | N | 58 | x | 79 |
| c | 37 | n | 59 | Y | 80 |
| D | 38 | O | 60 | y | 81 |
| d | 39 | o | 61 | Z | 82 |
| E | 40 | P | 62 | z | 83 |
| e | 41 | p | 63 | 0 | 84 |
| F | 42 | Q | 64 | 1 | 85 |
| f | 43 | q | 65 | 2 | 86 |
| G | 44 | R | 66 | 3 | 87 |
| g | 45 | r | 67 | 4 | 88 |
| H | 46 | S | 68 | 5 | 89 |
| h | 47 | s | 69 | 6 | 90 |
| I | 48 | T | 70 | 7 | 91 |
| i | 49 | t | 71 | 8 | 92 |
| J | 50 | U | 72 | 9 | 93 |
| j | 51 | u | 73 | | |
| K | 52 | V | 74 | | |
| k | 53 | | | | |
故可以根据原来的ascii推出现在定义的ASCII码:

  • (1) 假设字符为 A-Z,则有 ascii = (str1.charAt(i) - ‘A’) * 2 + 32;
  • (2) 假设字符为 a-z,则有 ascii = (str1.charAt(i) - ‘a’) * 2 + 33;
  • (3) 假设字符为 0-9,则有 ascii = str1.charAt(i) + 36;

(1) 用TreeSet存储字符串,因为TreeMap会自动给其排序
(2) 重写Compare方法,将其长度按照从小到大排序

3.代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
import java.util.*;
public class Main_1 {
public static void main(String[] args) {
String[]arr = {"abc","Abc","123","1","1bc","CBD","abcd","a"};
Set strSet = new TreeSet(new Comparator() {
@Override
public int compare(Object o1, Object o2) {
String str1 = (String) o1;
String str2 = (String) o2;
int temp = str1.length()-str2.length();
//如果两个数组的长度相等则直接按字典序排列,但是这个字典序不是常规的[0-9 A-Z a-z ]
//而是[AaBb-Zz 0-9]类型,故不能直接用str1.compareTo(str2)方法,要重新计算他的ascii码
//如果两个数组的长度相等则直接按字典序排列
if(temp==0){
int t1=0;
int t2=0;
for(int i=0;i<str1.length();i++){
char c1=str1.charAt(i);
char c2=str2.charAt(i);
//第一个字符串的新的ascii码计算
//A-Z范围,计算重新定义的ascii码
if(c1>='A'&&c1<='Z'){
t1 = (c1-'A') * 2 + 32;
//a-z范围,计算重新定义的ascii码
}else if(c1>='a'&&c1<='z'){
t1 = (c1-'a') * 2 + 33;
//0-9范围,计算重新定义的ascii码
}else if(c1>='0'&&c1<='9'){
t1 = c1 + 36;
}
//第二个字符串新的ascii计算
if(c2>='A'&&c2<='Z'){
t2 = (c2 -'A') * 2 + 32;
}else if(c2>='a'&&c2<='z'){
t2 = (c2-'a') * 2 + 33;
}else if(c2>='0'&&c2<='9'){
t2=c2 + 36;
}
if(t1!=t2)
break;
}
return t1-t2;
}else{
// 字符串长度不等,直接返回长度较小的,从小到大的字符串排序
return temp;
}
// return temp == 0 ?str1.compareTo(str2) : temp ;
}
});
for(int i = 0;i<arr.length;i++){
strSet.add(arr[i]);
}
for(Iterator it = strSet.iterator(); it.hasNext();){
System.out.print(it.next()+" ");
}
}

}

链表奇数位正序偶数位逆序

1.题目描述

设C={a1, b1, a2, b2…an, bn}为线性表,采用带头结点的hc单链表存放,设计一个算法,将其拆分为两个线性表,使得奇数位保持正序,偶数位转化为逆序。即:
A = {a1,a2….an}, B= {bn….b2,b1)

2.解题思路

  • 用odd和head存放奇数位数值,head用于指针的移动和将数值的添加到链表尾部,odd代表以-1为节点的奇数位链表
  • 用even和tail存放偶数位数值,tail用于指针的移动和将数值的添加到链表尾部,even代表以-1为节点的偶数位链表
  • odd.next即代表奇数位的线性表数值链起来的链表
  • even.next要进行链表反转,最后存到evenRes里面即代表偶数位的线性表数值链起来的链表

3.代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
//奇数位正序,偶数位逆序
public class Main {
static class ListNode {
int val;
ListNode next ;
public ListNode(int val) {
this.val = val;
}
}
private static void solution(ListNode temp) {
//奇数(正序输出)
ListNode head = new ListNode(-1);
ListNode odd = head;
//偶数(需要逆序输出)
ListNode tail = new ListNode(-1);
ListNode even = tail;
int i = 0;
while (temp != null){
//奇数位head
if(i % 2 !=0){
head.next = temp;
//指针移动
temp = temp.next;
head = head.next;
}else{ //偶数位逆序
tail.next = temp;
//指针移动
temp = temp.next;
tail = tail.next;
}
i++;
}
//这个怎么说捏
//假设是0--1--2--3
//遍历到这的时候为 odd : -1 -- 0 -- 2 -- 3 even : -1 -- 1 -- 3 ,所以要截断
//反正 tail 或者 head 都会包含链表的最后一个值,有一个是不需要的。
tail.next =null;
head.next = null;
//链表反转
ListNode evenRes = reverseList(even.next);
System.out.print("奇数位的排序为:");
printRes(odd.next);
System.out.println();
System.out.print("偶数位的排序为:");
printRes(evenRes);
}
//链表反转
private static ListNode reverseList(ListNode node) {
ListNode pre = null;
ListNode cur = node;
while (cur!=null){
ListNode next = cur.next; //记录下一个节点
cur.next = pre; //当前节点指向上一个节点
pre = cur; //记录当前节点
cur = next; //将下一个节点变成当前节点
}
return pre;
}
//打印结果
private static void printRes(ListNode node) {
while (node!=null){
System.out.print(node.val+" ");
node = node.next;
}
}

}

最长回文子串

1.题目描述

定义前后两端完全一致的字符串为对称字符串,如“abba”,”caddac”,编写程序,输出字符串”abcdefiiaaovivoovivcaideumncca”的最长对称子字符串。

2.解题思路

同leetcode_【5】最长回文子串:https://blog.csdn.net/qq_17556191/article/details/94620675
题解:
https://qiulig.github.io/%2F2019%2F05%2Fleetcode-5-%E6%9C%80%E9%95%BF%E5%9B%9E%E6%96%87%E5%AD%90%E4%B8%B2%2F
以下用动态规划重写:dp[i][j]代表的意思是索引从i到j的子字符串是否是回文,假设s = cbbd,则可以dp对应坐标索引下的子字符串:

i = 0 1 2 3
j = 0 c cb cbb cbbd
1 b bb bbd
2 b bd
3 d
1.动态规划初始化
- 对角线dp[i][i]:代表当前字符str.charAt(i),故初始化为true
- 相邻的两个字符初始化,两个字符相等就可以了。str.charAt(i) == str.charAt(j)

2.动态规划状态转移矩阵

  • 假设要求dp[0][2],首先还是要判断开头和结尾是否相等,也就是判断 str.charAt(0)==str.charAt(2),假如此时str.charAt(0)==str.charAt(2),我们还要再看剩下的子串是否回文, 我们可以直接从dp[i+1][j-1]来判断剩下的子串,把结果直接拿来用,判断是否是true(true表示回文)

    即有公式

    dp[i][j] = dp[i+1][j-1] &&str.charAt(0)==str.charAt(2) ?true:false

3.代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class Main {
public static void main(String[] args) {
String str = "abcdefiiaaovivoovivcaideumncca";
solution(str);
}
public static void solution(String str){
char arr[] = str.toCharArray();
//dp[i][j]代表i~j的字符串的回文长度
boolean [][]dp = new boolean[str.length()][str.length()];
//初始化对角线
for(int i = 0;i<str.length();i++){
dp[i][i] = true;
}
//初始化相邻的两个字符是否为回文
for(int i = 0;i<=arr.length-2;i++){
dp[i][i+1] = str.charAt(i) == str.charAt(i+1)?true:false;
}
int max = 1;
String res = "";
for(int i = 0;i<arr.length;i++){
for(int j = i+2;j<arr.length;j++){
//两端的数相等以及中间的数是回文
dp[i][j] = dp[i+1][j-1] && str.charAt(i) == str.charAt(j) ? true:false;
if(dp[i][j] == true && j - i + 1>max){
max = j-i+1;
res = str.substring(i,j+1);
}
}
}
// System.out.println(max);
System.out.println(res);
}
}

整理自牛客资料技术篇

个人想法,如有错误请指出!!

文章目录
  1. 1. 字符串排序
    1. 1.1. 1.题目描述
    2. 1.2. 2.解题思路
    3. 1.3. 3.代码
  2. 2. 链表奇数位正序偶数位逆序
    1. 2.1. 1.题目描述
    2. 2.2. 2.解题思路
    3. 2.3. 3.代码
  3. 3. 最长回文子串
    1. 3.1. 1.题目描述
    2. 3.2. 2.解题思路
    3. 3.3. 3.代码
| 139.6k