链表
Posted wwj99
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了链表相关的知识,希望对你有一定的参考价值。
链表的回文结构
对于一个链表,请设计一个时间复杂度为O(n),额外空间复杂度为O(1)的算法,判断其是否为回文结构。
给定一个链表的头指针A,请返回一个bool值,代表其是否为回文结构。保证链表长度小于等于900。
测试样例:
1->2->2->1
返回:true
Java
具体实现
/**
* recognize Palindrome number
* @return
*/
public boolean judgePalindrome() {
if(this.head == null) { //判断链表非空
return false;
}else if(this.head.next == null) {
return true;
}
Node first = this.head;
Node second = this.head;
while(first != null && first.next!= null) { //寻找中间节点
first = first.next.next;
second = second.next;
}
Node p = second.next; //节点 second 即为中间的节点,若链表为偶数则表示中间第二个
Node pNext = p.next;
while(p != null) { //将中间节点以后的部分的链表逆置
p.next = second;
second = p;
p = pNext;
if(p != null) {
pNext = p.next;
}
}
while(head != second) {
if(head.data != second.data) {
return false;
}
if(head.next == second) {
return true;
}
head = head.next;
second = second.next;
}
return true;
}
C++
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};*/
classPalindromeList {
public:
bool chkPalindrome(ListNode* A) {
// write code here
//A为空时false,A为单个节点时true
if(A==NULL){
returnfalse;
}elseif(A->next==NULL){
returntrue;
}
//快慢指针找出中间节点
ListNode* quick=A;
ListNode* slow=A;
while(quick!=NULL&&quick->next!=NULL){
quick=quick->next->next;
slow=slow->next;
}
//将中间节点后的指针反转
ListNode* p=slow->next;
ListNode* p1=p->next;
while(p!=NULL){
p->next=slow;
slow=p;
p=p1;
p1=p1->next;
}
//从头、尾指针向中间遍历,判断A是否是回文
while(A!=slow){
if((A->val)!=(slow->val)){
returnfalse;
}else{
if(A->next==slow){
returntrue;
}
A=A->next;
slow=slow->next;
}
}
returntrue;
}
};
two-sum
https://www.nowcoder.com/questionTerminal/20ef0972485e41019e39543e8e895b7f
给出一个整数数组,请在数组中找出两个加起来等于目标值的数,
你给出的函数twoSum 需要返回这两个数字的下标(index1,index2),需要满足 index1 小于index2.。注意:下标是从1开始的
假设给出的数组中只存在唯一解
例如:
给出的数组为 {2, 7, 11, 15},目标值为9
输出 ndex1=1, index2=2
Java
import java.util.HashMap;
public class Solution {
public int[] twoSum(int[] numbers, int target) {
int n = numbers.length;
int[] result = new int[2];
//map里面放 键为target-每个数的结果 值为下标
//每次放入的时候看是否包含 当前值
//有的话说明当前值和已包含的值下标的那个元素为需要的结果
HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
for(int i=0;i<n;i++){
if(map.containsKey(numbers[i])){
result[0] = map.get(numbers[i])+1;
result[1] = i+1;
break;
}
else{
map.put(target - numbers[i], i);
}
}
return result;
}
}
C++
class Solution {
public:
vector<int> twoSum(vector<int> &numbers, int target) {
unordered_map<int, int> hashtable;
vector<int> result;
for(int i=0; i<numbers.size(); i++){
hashtable[numbers[i]] = i;
}
for(int i=0; i<numbers.size(); i++){
const int diff = target - numbers[i];
if(hashtable.find(diff) != hashtable.end() && hashtable[diff] > i){
result.push_back(i+1);
result.push_back(hashtable[diff]+1);
break;
}
}
return result;
}
};
奇数位丢弃
https://www.nowcoder.com/questionTerminal/196141ecd6eb401da3111748d30e9141
对于一个由0..n的所有数按升序组成的序列,我们要进行一些筛选,每次我们取当前所有数字中从小到大的第奇数位个的数,并将其丢弃。重复这一过程直到最后剩下一个数。请求出最后剩下的数字。
输入
500 //每组数据一行一个数字,为题目中的n(n小于等于1000)。
输出
255 //一行输出最后剩下的数字。
C
因为是从0开始,所以第一轮移走的是二进制下最右边为0的位置(从0开始的偶数位置)上的数,然后我们发现第二轮各个number的位置等于number/2,即从number位置到number>>1位置,这时候我们依然移走二进制下最右边为0的位置(1(01) 5(101) 9(1001) ……它们第二轮对应的位置是0, 2, 4),最后剩一个数肯定是0到n中二进制下1最多的那个数,因为它每次的位置都是奇数位置。代码如下
#include <cstdio>
int main()
{
int n;
while(scanf("%d", &n) != EOF){
int b = 1;
while(b <= n + 1){
b <<= 1;
}
printf("%d
", (b >> 1) - 1);
}
return 0;
}
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while (sc.hasNext()) {
int n = sc.nextInt();
List<Integer> list = new ArrayList<Integer>();
for (int i = 0; i <= n; i ++ )
list.add(i);
while (list.size() != 1) {
// 从0开始list移除一次,i再加一次,i始终指向奇数位
for (int i = 0; i < list.size(); i = i + 1)
list.remove(i);
}
System.out.println(list.get(0));
}
}
}
//常规做法,比较直观,用数组a每次循环清楚记录了每次删除后剩余的元素。
#include<iostream>
using namespace std;
int main(){
int n,i,a[1001],count;
while( cin >> n ){
for(i=0;i<=n;i++)
a[i] = i;
count = n+1;
while( count != 1 ){
for(i=0;2*i+1<count;i++)
a[i] = a[2*i+1];
count = i;
}
cout << a[0] << endl;
}
}
//特殊思路,每次删除所在数组位置的二进制最右端为0的元素。如0(0)2(10)4(100)
//剩余的元素1(01)3(11)5(101)下一次其位置变成了之前位置左移一次后的
// 1(1) 3(10) 5(10) 然后继续按之前规则删除最右端为0的元素。故原始序列中,谁的//二进制下从右往左数,1最多,则最后删除,因每次删除移位后,最右端仍然为1,会保留
#include<iostream>
using namespace std;
int main(){
int n;
while( cin >> n ){
int b = 1;
while( b <= n )
/*b = (b<<1) + 1;//或者 用*/ b = b*2 +1;
cout << (b>>1) << endl;
}
}
以上是关于链表的主要内容,如果未能解决你的问题,请参考以下文章
NC41 最长无重复子数组/NC133链表的奇偶重排/NC116把数字翻译成字符串/NC135 股票交易的最大收益/NC126换钱的最少货币数/NC45实现二叉树先序,中序和后序遍历(递归)(代码片段