字符串排序
请对组字符串进行排序,字符串由大小写字母和数字组成,需要满足以下比较规则
比如:
abc Abc 123 1bc CBD abed a
排序后结果为:
a 1 Abc abc CBD 1bc 123 abcd
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) 用TreeSet存储字符串,因为TreeMap会自动给其排序
(2) 重写Compare方法,将其长度按照从小到大排序
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()+" ");
}
}
}
链表奇数位正序偶数位逆序
设C={a1, b1, a2, b2…an, bn}为线性表,采用带头结点的hc单链表存放,设计一个算法,将其拆分为两个线性表,使得奇数位保持正序,偶数位转化为逆序。即:
A = {a1,a2…an}, B= {bn…b2,b1)
- 用odd和head存放奇数位数值,head用于指针的移动和将数值的添加到链表尾部,odd代表以-1为节点的奇数位链表
- 用even和tail存放偶数位数值,tail用于指针的移动和将数值的添加到链表尾部,even代表以-1为节点的偶数位链表
- odd.next即代表奇数位的线性表数值链起来的链表
- even.next要进行链表反转,最后存到evenRes里面即代表偶数位的线性表数值链起来的链表
//奇数位正序,偶数位逆序
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;
}
}
}
最长回文子串
定义前后两端完全一致的字符串为对称字符串,如“abba”,“caddac”,编写程序,输出字符串"abcdefiiaaovivoovivcaideumncca"的最长对称子字符串。
同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
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);
}
}
整理自牛客资料技术篇
个人想法,如有错误请指出!!