利用字符串转换和数学法
在leetcode上刷到这样一道题目,很明显:
(1)该数字 < 0,输出的是false,
(2)比如10、120等%10 = 0的,也返回false,但是此时要注意:0%10也是等于0的,而0也是回文数!
(3)问题的关键在:如何判断左边和右边是对称的呢?
A、将数字转换成字符串
B、数学法:利用求余、整除。
1. 将数字转换成字符串
方法一:
基本思想:将该数字转换为字符串,直接调用java中的字符串的反转函数
比如数字12345,调用函数得54321
方法二:
基本思想:将该数字转换为字符串,再利用字符串的charAt()方法从字符串的两端逐一判断,若不同则直接返回错误。
比如12345,用first、last指针标记,每轮判charAt(first)是否与charAt(last)相同,1和5不同直接返回false。
方法三:
基本思想:将该数字转换为字符串,然后切分放入数组,两端逐一比较。该方法跟方法二类似,就比方法二多了切片放入数组这一步。
2、数学法:利用求余、整除
方法一:将整个数翻转,与之前得数比较
比如12345,翻转后为54321,而12345 != 54321
方法二:翻转一半的数,然后用其中一半与另一半比较,这个比较像链表判断回文串的做法(链表法,下面再说)
比如判断数字12321。将后两位翻转后为12,与前两位相等。数字123456,将后三位翻转后为654,与前三位不等
变量halfReverse来存放翻转数字的后n/2位,while(x > halfReverse)这个条件很妙, 在翻转过程中x < halfReverse 说明已经翻转了一半的数位。
最后当数字长度为偶数时,直接比较x == halfReverse;当数字长度为奇数时,我们可以通过revertedNumber/10去除处于中位的数字。
利用栈、链表
这里形参都是字符串,若是数字的话,需要再写一个数字转换成字符串的函数。
1、栈
基本思想:利用栈的先进后出思想,将字符串的一半入栈,然后每次都利用字符串的后半部分与栈顶比较,若相同则弹出栈顶元素,继续比较下一个元素。
比如abcba,入栈ab,因为字符串是奇数个,说明最中间的哪个不用比较,指针需要格外的后移一位,比较字符串ba,此时栈顶元素为b,字符串指针指向b,两者相同,栈顶元素弹出,字符串指针后移。栈顶元素变为a,字符串指针指向的也是a,栈顶元素弹出。循环结束,说明是回文串。
//节点类
class Node1<T>{
T data;
Node1<T> next;
Node1(){
this(null);
}
Node1(T data){
this.data = data;
this.next = null;
}
}
//链栈类
class LinkStack1<T>{
private Node1<T> top;
public boolean isEmpty() {
return top == null;
}
public void push(T data) {
Node1<T> p = new Node1<T>(data);
p.next = top;
top = p;
}
public T pop() {
if (isEmpty())
return null;
else {
Node1<T> p = top;
top = top.next;
return p.data;
}
}
public T peek() {
if(!isEmpty())
return top.data;
else
return null;
}
}
public class isPalindrome {
//判断是否为回文串的函数
public void stack(String str) { //判断是否为回文串
String newstr = str.toUpperCase(); //将字符串的单词转换为小写字母
String[] strs = newstr.split(""); //将字符串拆分成放入数组
int length = strs.length / 2;
LinkStack1<String> L= new LinkStack1<String>();
for(int i = 0; i < length; i++) { //一半入栈
L.push(strs[i]); //进栈
}
if (strs.length % 2 != 0)
length++;
for(int i = length; i < strs.length; i++) {
if (L.peek().equals(strs[i])) {
L.pop();
}
else {
return;
}
}
System.out.println(str + " 是回文串!");
}
}
2、 链表
基本思想:利用双向循环链表的双向和循环性,用head.next从当头指针,实现从头开始,用head.period从当尾指针,实现从尾部开始。这个时候何时结束循环很关键。
class LinkList{ //用链表判断是否为回文串
Node head = new Node(); //头指针
class Node{ //节点类(双向循环)
String data;
Node next = null;
Node prior = null;
Node(){
this(null);
}
Node(String data){
this.data = data;
}
}
Node temp = head; //记录尾结点
public void append(String data) { //尾插法
Node cur = new Node(data);
temp.next = cur;
cur.prior = temp;
temp = temp.next;
}
public void cir() { //形成循环链表
temp.next = head;
head.prior = temp;
}
public void HTpoiter(String str){ //头尾指针判断
String newstr = str.toUpperCase(); //将字符串的单词转换为小写字母
String[] strs = newstr.split(""); //将字符串拆分成放入数组
for(int i = 0; i < strs.length; i++) {
append(strs[i]); //形成双向链表
}
cir(); //形成双向循环链表
Node t1 = head.next;
Node t2 = head.prior;
int cnt = 0; //结点个数统计
while(cnt != strs.length / 2) { //等于一半终止
if (t1.data.equals(t2.data)) {
t1 = t1.next;
t2 = t2.prior; //字符相同则比较下一个
cnt++;
}
else {
System.out.println(str + " 不是回文串!"); //不同直接输出
return;
}
}
System.out.println(str + " 是回文串!");
}
}