剑指offer66题(Python)——第三天

あなたほばかですか.

13、打印1到最大的n位数

    打印1到最大的n位数,如n=3时打印1到999 
思路:求出最大的n位数,然后依次打印,但当n十分大事会出问题。这里涉及到大数问题。
n = 2
num = 1
for i in range(n):
    num = num*10
for i in range(1,num):
    print i
一个更完善的思路:  用字符串表示数字,进行进位,全排列递归输出,略复杂。
用字符串解决大数问题的思路大致如下:
        字符串中的每个字符都是‘0’到‘9’之间的某个字符,用来表示数字中的一位。数字最大是n位,故需要一个n+1的字符串,最后一个为结束符号‘\0’。当实际数字不够n位的时候,在字符串的前半部分补0。如果在数字前面补0的话,就会发现n位所有十进制数其实就是n个从‘0’到‘9’的全排列。也就是说,把数字的每一位都从‘0’到‘9’排列一遍,就可以得到所有的十进制数。但是在打印的时候,数字排在前面的0不打印。
可以参考大佬的代码:Python实现代码

14、在O(1)时间删除链表结点

思路:这个首先想到的是顺序查找,复杂度为O(n),但是不满足要求啊。

好的解决方案是这么个思路:

        如果要删除结点i,先把i的下一个节点j的内容复制到i,然后把i的指针指向节点j的下一个节点。此时再删除节点j。如果删除的节点位于链表的尾部,则从链表的头节点开始,顺序遍历得到该节点的前序节点,并完成删除操作。如果链表中只有一个节点,此时删除节点后,还需要把链表的头节点设置为NULL。

        还有一点需要注意,上述思路基于要删除的点存在在链表中,而我们需要O(n)的时间才能判断链表中是否有该节点。面试时要告诉面试官这个假设。

综上,进阶思路: 
1、判断要删除的节点后是否有节点,若有节点,则将该节点内容复制到要删除的节点,并删除该节点 
2、若链表中只有一个节点,则删除该节点 
3、若要删除的节点后面没有节点(即该节点为最后一个),则遍历到该节点前一位并删除该节点

class ListNode:
    def __init__(self, x = None):
        self.val - x
        self.next = None
    def __del__(self):
        self.val = None
        self.next = None

class Solution:
    def DeleteNode(self, pListHead, pToBeDeleted):
        if not pListHead or not pToBeDeleted:
            return None

        if pToBeDeleted.next != None: #如果要删除的节点后面不为空,则将下一个节点复制
            pToBeDeleted.val = pToBeDeleted.next.val
            pToBeDeleted.next = pToBeDeleted.next.next
            pToBeDeleted.next.__del__()
        elif pListHead == pToBeDeleted:
            pToBeDeleted.__del__()
            pListHead.__del__()
        else:
            pNode = pListHead
            while pNode != pToBeDeleted:
                pNode = pNode.next
            pNode.next = None
            pToBeDeleted.__del__()
代码来自于 https://blog.csdn.net/slibra_l/article/details/78151979


15、调整数组顺序使奇数位于偶数前面

输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。
思路:首先送上我的low代码,没看懂书上牛逼的算法。。。
def reOrderArray(array):
    # write code here
    ji = []
    ou = []
    alle = []
    x=[]
    for i in array:
        if i % 2 == 0:
            ou.append(i)
            ou.sort()
        else:
            ji.append(i)
            ji.sort()
    alle.append(ji)
    alle.append(ou)
    for i in alle:
        for j in i:
            x.append(j)
    return x
class Solution {
public:
    void reOrderArray(vector<int> &array) {
        vector<int> result;
        int num=array.size();
        for(int i=0;i<num;i++)
            {
            if(array[i]%2==1)
                result.push_back(array[i]);
        }
        for(int i=0;i<num;i++)
            {
            if(array[i]%2==0)
                result.push_back(array[i]);
        }
        array=result;
    }
};

16、链表中倒数第K个结点

输入一个单向链表,输出该链表中倒数第k个结点。
思路: 两个指针,先让第一个指针和第二个指针都指向头结点,然后再让第一个指正走(k-1)步,到达第k个节点。然后两个指针同时往后移动,当第一个结点到达末尾的时候,第二个结点所在位置就是倒数第k个节点了。
# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def FindKthToTail(self, head, k):
        # write code here
        l=[]
        while head!=None:
            l.append(head)
            head=head.next
        if k>len(l) or k<1:
            return
        return l[-k]
时间复杂度O(n),一次遍历即可
public class Solution {
    public ListNode FindKthToTail(ListNode head,int k) {
        ListNode pre=null,p=null;
        //两个指针都指向头结点
        p=head;
        pre=head;
        //记录k值
        int a=k;
        //记录节点的个数
        int count=0;
        //p指针先跑,并且记录节点数,当p指针跑了k-1个节点后,pre指针开始跑,
        //当p指针跑到最后时,pre所指指针就是倒数第k个节点
        while(p!=null){
            p=p.next;
            count++;
            if(k<1){
                pre=pre.next;
            }
            k--;
        }
        //如果节点个数小于所求的倒数第k个节点,则返回空
        if(count<a) return null;
        return pre;
            
    }
}


17、反转链表

递归的方法其实是非常巧的,它利用递归走到链表的末端,然后再更新每一个node的next 值 ,实现链表的反转。而newhead 的值没有发生改变,为该链表的最后一个结点,所以,反转后,我们可以得到新链表的head。

注意关于链表问题的常见注意点的思考:

1、如果输入的头结点是 NULL,或者整个链表只有一个结点的时候

2、链表断裂的考虑

# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    # 返回ListNode
    def ReverseList(self, pHead):
        # write code here
        if pHead==None or pHead.next==None:
            return pHead
        last = None
        while pHead:
            tmp = pHead.next
            pHead.next=last
            last = pHead
            pHead=tmp
        return last
/*
struct ListNode {
	int val;
	struct ListNode *next;
	ListNode(int x) :
			val(x), next(NULL) {
	}
};*/
class Solution {
public:
    ListNode* ReverseList(ListNode* pHead) {
         //如果链表为空或者链表中只有一个元素
        if(pHead==NULL||pHead->next==NULL) return pHead;
        //先反转后面的链表,走到链表的末端结点
        ListNode* pReverseNode=ReverseList(pHead->next);
        //再将当前节点设置为后面节点的后续节点
        pHead->next->next=pHead;
        pHead->next=NULL;
        return pReverseNode;
    }
};

18、合并两个排序的链表

输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。

思路:

初始化两个链表头,其中一个表头用以记录两个单调递增链表比较后的结果,另一个用以返回结果。

用while循环:

①如果两个链表不为空,比较进行,并将小的那个赋给合并的链表头。小表头继续走一步,合并表头继续走一步。

②如果两个链表有其一为空,那么跳出循环,并将另一不为null的链表的后续部分赋给合并链表。

# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    # 返回合并后列表
    def Merge(self, pHead1, pHead2):
        # write code here
        mergeHead = ListNode(0)
        p = mergeHead
        while pHead1 and pHead2:
            if pHead1.val >= pHead2.val:
                mergeHead.next = pHead2
                pHead2 = pHead2.next
            else:
                mergeHead.next = pHead1
                pHead1 = pHead1.next                  
            mergeHead = mergeHead.next
        if pHead1:
            mergeHead.next = pHead1
        elif pHead2:
            mergeHead.next = pHead2
        return p.next

递归版本

public ListNode Merge(ListNode list1,ListNode list2) {
       if(list1 == null){
           return list2;
       }
       if(list2 == null){
           return list1;
       }
       if(list1.val <= list2.val){
           list1.next = Merge(list1.next, list2);
           return list1;
       }else{
           list2.next = Merge(list1, list2.next);
           return list2;
       }       
   }


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值