1.字符串排序
【题目描述】请对组字符串进行排序,字符串由大小写字母和数字组成,需要满足以下比较规则:
- 长度不同时,长度较短在排前面
- 长度相同时,按照字典顺序排列(AaBb-Zz, 0-9顺序),即大写字母在小写字母前,数字排在字母后,要求时间复杂度为O(nlogn)。
比如:
“abc”,“Abc”,“123”,“1”,“1bc”,“CBD”,“abcd”,“a”
abc Abc 123 1bc CBD abed a
排序后结果为:
a 1 Abc abc CBD 1bc 123 abcd
解题思路:
将字符的顺序重新排列,实现cmp函数计算ASCII码值做相应的处理,处理后排序为(AaBb-Zz, 0-9顺序)
字符对应的ASCII码值:
字符 | ASCII码值 | 字符 | ASCII码值 | 字符 | ASCII码值 |
---|---|---|---|---|---|
A-Z | 65-90 | a-z | 97-122 | 0-9 | 48-57 |
需要处理过后的字符顺序:
字符 | 处理后返回值 | 字符 | 处理后返回值 | 字符 | 处理后返回值 | 字符 | 处理后返回值 |
---|---|---|---|---|---|---|---|
A | 0 | I | 16 | Q | 32 | Y | 48 |
a | 1 | i | 17 | q | 33 | y | 49 |
B | 2 | J | 18 | R | 34 | Z | 50 |
b | 3 | j | 19 | r | 35 | z | 51 |
C | 4 | K | 20 | S | 36 | 0 | 52 |
c | 5 | k | 21 | s | 37 | 1 | 53 |
D | 6 | L | 22 | T | 38 | 2 | 54 |
d | 7 | l | 23 | t | 39 | 3 | 55 |
E | 8 | M | 24 | U | 40 | 4 | 56 |
e | 9 | m | 25 | u | 41 | 5 | 57 |
F | 10 | N | 26 | V | 42 | 6 | 58 |
f | 11 | n | 27 | v | 43 | 7 | 59 |
G | 12 | O | 28 | W | 44 | 8 | 60 |
g | 13 | o | 29 | w | 45 | 9 | 61 |
H | 14 | P | 30 | X | 46 | ||
h | 15 | p | 31 | x | 47 |
解题代码:
public static void main(String[] args) {
String[] input = {"abc", "Abc", "123", "1", "1bc", "CBD", "abcd", "a"};
sort(input);
for (String s:input){
System.out.println(s);
}
}
public static void sort(String []input){
quickSort(input,0,input.length-1);
}
// 快排
public static void quickSort(String []data,int left,int right){
if (left>right){
return;
}
int i;
int j;
String tmp=data[left];
i=left;
j=right;
while (i!=j){
// 从右至左开始找到j位置比tmp小的串
while (cmp(data[j],tmp)>=0&&i<j){
j--;
}
// 从左至右开始找到i位置比tmp大的串
while (cmp(data[i],tmp)<=0&&i<j){
i++;
}
if (i<j){
String t;
t=data[i];
data[i]=data[j];
data[j]=t;
}
}
// i==j,将tmp放入适合的位置
data[left]=data[i];
data[i]=tmp;
quickSort(data,left,i-1);
quickSort(data,i+1,right);
}
public static int cmp(String left,String right){
if (left.length()!=right.length()){
return left.length()-right.length();
}
// 字符串长度相等的情况
int len=left.length();
for (int i=0;i<len;i++){
char l=left.charAt(i);
char r=right.charAt(i);
// 直到两者中遍历到不同的字符
if (l==r){
continue;
}
// 获取字符的值
int lcv=getCharValue(l);
int rcv=getCharValue(r);
if (lcv!=rcv){
return lcv-rcv;
}
}
// 相等
return 0;
}
// A返回0,a返回1,B返回2,b返回3...
public static int getCharValue(char c){
// a-z
if (c>='a'){
return (c-'a')*2+1;
// A-Z
}else if (c>='A'){
return (c-'A')*2;
}
// 如果c为数字
return c-'0'+52;
}
2.链表拆分(链表奇数位正序偶数位逆序)
【题目描述】设C={a1, b1, a2, b2…an, bn}为线性表,采用带头结点的hc单链表存放,设计一个算法,将其拆分为两个线性表,使得奇数位保持正序,偶数位转化为逆序。即:
A = {a1,a2…an}, B= {bn…b2,b1)
解题思路:
奇数使用尾插法,偶数使用头插法
解题代码:
// 思路:奇数使用尾插法,偶数使用头插法
static class ListNode {
int val;
ListNode next ;
public ListNode(int val) {
this.val = val;
}
}
public static void main(String[] args) {
//测试用例链表
ListNode head=new ListNode(1);
head.next=new ListNode(2);
head.next.next=new ListNode(3);
head.next.next.next=new ListNode(4);
head.next.next.next.next=new ListNode(5);
head.next.next.next.next.next=new ListNode(6);
head.next.next.next.next.next.next=new ListNode(7);
System.out.print("原来的链表:");
printListNode(head);
System.out.println();
oddEvenList(head);
}
public static void oddEvenList(ListNode node) {
if (node == null) {
return;
}
// 奇数 奇数,使用尾插法
ListNode odd= new ListNode(-1);
ListNode oddHead = odd;
// 偶数
ListNode evenHead = null;
int i = 0;
while (node != null){
// 奇数,使用尾插法
if((i+1) % 2 !=0){
odd.next = node;
node = node.next;
odd = odd.next;
}else{
// 使用头插法,因为是逆序
ListNode tmp=new ListNode(node.val);
tmp.next=evenHead;
evenHead=tmp;
node = node.next;
}
i++;
}
// 处理
oddHead=oddHead.next;
odd.next=null;
System.out.print("奇数链表:");
printListNode(oddHead);
System.out.println();
System.out.print("偶数链表:");
printListNode(evenHead);
}
// 打印结果
private static void printListNode(ListNode node) {
while (node!=null){
System.out.print(node.val+" ");
node = node.next;
}
}
结果:
3.最长对称子串(最长回文子串)
【题目描述】定义前后两端完全一致的字符串为对称字符串,如“abba”,“caddac”,编写程序,输出字符串"abcdefiiaaovivoovivcaideumncca"的最长对称子字符串。
解题思路:动态规划
设状态dp[j][i]表示索引j到索引i的子串是否是回文串。则转移方程为:
则dp[j][i]为true时表示索引j到索引i形成的子串为回文子串,且子串起点索引为j,长度为i - j + 1。
算法时间复杂度为O(N ^ 2)。
解题代码:(这里置1来代表true)
public String longestPalindrome(String s) {
if(s==null||s.length()<=0) return "";
int n=s.length();
int [][]dp=new int[n][n];
int start=0;
int max=1;
for(int i=0;i<n;i++) {
for(int j=0;j<=i;j++) {//注意小于等于i!!! 因为要构建dp[i][i]=1
if(j==i) {
dp[i][i]=1;
}else if(i-j==1&&s.charAt(i)==s.charAt(j)){
dp[j][i]=1;
}else if(i-j>1&&s.charAt(i)==s.charAt(j)&&dp[j+1][i-1]==1){
dp[j][i]=1;
}
//构建完成之后,查看是否更新最大值
if(dp[j][i]==1&&max<i-j+1) {
max=i-j+1;
start=j;
}
}
}
return s.substring(start, max+start);
}