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.代码

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.代码

//奇数位正序,偶数位逆序
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-最长回文子串%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.代码

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);
    }
}

整理自牛客资料技术篇

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

你可能感兴趣的:(笔试)