zoukankan      html  css  js  c++  java
  • 数据结构与算法——链表(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
    ", (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;
        }
    }
    
  • 相关阅读:
    玲珑学院-ACM比赛1014
    扩展欧几里得算法
    中国剩余定理(孙子定理)及实现----原理详解
    搞懂树状数组
    HDU3792---Twin Prime Conjecture(树状数组)
    树状数组 模板
    HDU1541--Stars(树状数组)
    HDU4046--Panda(树状数组)
    CCF-201604-1-折点计数
    CCF-201604-2-俄罗斯方块
  • 原文地址:https://www.cnblogs.com/wwj99/p/12200471.html
Copyright © 2011-2022 走看看