链表(2)

链表的回文结构

对于一个链表,请设计一个时间复杂度为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\n", (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;
    }
}

猜你喜欢

转载自www.cnblogs.com/wwj99/p/12200471.html