力扣刷題記錄(一)


 

今天開始正式刷題,為找工作做准備,這篇博客用來記錄一下;刷題順序是先刷hot題目前100個

1.兩數之和:

比較簡單,一次就做出來。

思路:python的字典是哈希存儲的,看了一下dict內置方法只有has_key,所以將值作為key,下標作為value,存儲字典,然后遍歷列表,以當前值為基准,用has_key判斷(target-當前值)是否存在,存在則返回相應的下標即可。,代碼如下:

class Solution(object): def twoSum(self, nums, target): """ :type nums: List[int] :type target: int :rtype: List[int] """ info={} # 將數據存入到字典當中
        for i in range(len(nums)): info[nums[i]] = i for i in range(len(nums)): temp = target-nums[i] if info.has_key(temp): return [info[temp],i]

 2.兩數相加

給了兩個鏈表,代表兩個數字,逆序存儲。將兩個數字相加,存儲成相同的鏈表格式,返回。

第一次沒做出來,看了答案才會的,第二次做有一些小bug,認真分析之后對一些細節地方理解更深刻了。

思路:不需要將兩個數算出來然后相加,只需要將每一位相加,加的過程中判斷是否有進位,如果有進位的話就多加一個1。另外注意這塊沒有新創建節點,而是直接使用a,b已經存在的節點,更改他們的值,注意這里是默認使用a節點,a為空了則使用b節點。另外注意循環最后一句是在拼接目標鏈表,而這一句

p = (a==null?b:a);是在更改目標鏈表的值為正確的值。

 

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        ListNode p = null;
        ListNode a = l1;
        ListNode b = l2;
        int carry=0;   //進位標志
        int val;    //每一位的和
        while(a!=null || b!=null){
            val = (a==null?0:a.val) + (b==null?0:b.val) + carry;  //計算該位的值
            carry = val>=10?1:0;
            val = val%10;  //必須是小於10的
            p = (a==null?b:a);    //讓p指向當前a,b里面不為空的,默認是a
            p.val = val;  //更新節點的值
            a = (a==null?null:a.next);  //后移節點
            b = (b==null?null:b.next);
            p.next=(a==null?b:a);   //將p也后移一下,這一部無所謂,只是單純的后移一下,
        }        
        //最后的進位判斷
        if(carry>0){
            p.next=new ListNode(1);
        }
        return l1;
    }
}

 

 好久不寫了,一方面考試太多了,另一方面也是自己太懶了,買了一本《劍指offer》,配合這個好好刷一下題,另外准備按照題目難度刷

1.合並二叉樹

題目描述:將兩個二叉樹進行合並, 如果兩個樹的當前節點都不為空,則將其值合並,否則取其中不為空的節點,最后返回一個新的樹。

思路:雖然是一個比較簡單的題,但是數據結構都忘了好多,開始還想了半天。總體上直接使用原來的內存空間就可以了, 這樣就不需要再去申請內存創建新的節點了。采用先序遍歷的方法遍歷這棵樹,當前節點如果有一個為空的,則返回另一個不空的,默認先判斷t1,如果兩個都不空的話就將值累加給t1的當前節點之后返回t1節點,都為空的情況已經包含在了第一種情況。

對一種情況的說明:因為我們是采用拼接的方法得到最終生成樹的,所以並不是必須要遍歷完兩顆樹的所有節點,比如如果當前t1.left為空,t2.left不為空,則將t2.left賦給t1.lft,並且t2.left的所有子節點也都跑到了t1.left之下,所以之后就就不需要再遍歷t2.left的子節點了,因為t1.left沒有子樹,之后遍歷的取值肯定都是t2的。

代碼比較簡單:
遞歸的方法:

class Solution {
    public TreeNode mergeTrees(TreeNode t1, TreeNode t2) {
        //先序遍歷兩顆樹,將和累加到A樹當中,如果其中一個空的話,則直接返回另外一個不空的,並且可以把那個不為空的子節點直接擴展到其中去
        if(t1 == null){
            return t2;
        }
        if(t2 == null){
            return t1;
        }
        t1.val += t2.val;   //合並當前節點
        t1.left = mergeTrees(t1.left, t2.left);  //合並左子樹,一個為空則不合並
        t1.right = mergeTrees(t1.right, t2.right);   //合並右子樹
        return t1;
    }
}
View Code

面試時候如果你寫遞歸的話,面試官會問你優化方法,所以還是老老實實的把非遞歸的也看一下:

非遞歸使用棧來完成,初始時候把兩個根節點作為一項入棧,之后每一次從棧之中取出一個元素,判斷該元素之中的兩個節點為null的情況,

1.都為null的話,則無需再對這兩個節點的子樹進行討論,跳過本次循環

2.如果有一個為空或者兩個都不為空, 則將值累加到t1節點當中,並對t1.left和t1.right進行考察,如果為空的話,則直接將t2.left或者t2.right賦值給t1對應節點,如果不為空,則將t1.left和t2.left作為一項append到棧之中,之后進行考察。

代碼:   !!!!!!!這個非遞歸的代碼是錯誤的,之前沒有認真看,今天再次回顧時候才發現,錯誤代碼就放在這里,以示警戒。

錯誤地方我不想,大家自己拿到leetcode上面運行一下,漏洞百出,之前太不仔細了,這個非遞歸代碼就是cv的,當時也沒注意是錯的。

class Solution:
    def mergeTrees(self, t1: TreeNode, t2: TreeNode) -> TreeNode:
        if not t1:
            return t2
        stack = [[t1,t2]]
        while stack:
            t = stack.pop()
            if (not t[0]) and (not t[1]):
                continue
            t[0].val += t[1].val
            if not t[0].left:
                t[0].left = t[1].left
            else:
                stack.append([t[0].left,t[1].left])
            if not t[0].right:
                t[0].right = t[1].right
            else:
                stack.append([t[0].right, t[1].right])
        return t1
View Code

附上自己想的正確的代碼,用棧來轉換遞歸的先序遍歷,對於當前出棧元素有四種討論,(都為空,(t[0非空,t[1]空)),(t[0]空,t[1]不空), (都不空),前兩種情況做相同的處理,都是直接continue,第二種情況需要將t[1]嫁接到t[0]處,第三種情況相加節點,並添加新的元組到棧中。

代碼如下:

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def mergeTrees(self, t1: TreeNode, t2: TreeNode) -> TreeNode:
        if not t1:
            return t2
        stack = [(t1,t2)]
        while stack:
            t = stack.pop()
            if (not t[0] and not t[1]) or (t[0] and not t[1]):
                continue
            elif t[0] and t[1]:
                t[0].val += t[1].val
                if not t[0].left:
                    t[0].left = t[1].left
                else:
                    stack.append((t[0].left,t[1].left))
                if not t[0].right:
                    t[0].right = t[1].right
                else:
                    stack.append((t[0].right, t[1].right))
            elif not t[0] and t[1]:
                t[0] = t[1]

        return t1

 當然這個if,else的排列可以深究一下,哈夫曼樹,這里不說了。

2.兩個整數之間的漢明距離指的是這兩個數字對應二進制位不同的位置的數目。

給出兩個整數 x 和 y,計算它們之間的漢明距離。

題目思路:這個題比較簡單,就是比較二進制之中不相同的位的個數,要么直接異或運算,然后計算1的個數,要么先將他們轉換為2進制之后計算不相同的位的個數,注意轉換時候必須讓他們總的位數相同,所以用or條件判斷

class Solution: def hammingDistance(self, x: int, y: int) -> int: """ 首先將兩個數字都轉換為2進制數字存儲為列表,之后找出來不一樣的項的個數 或者直接進行異或運算,計算結果里面1的個數即可 """ res = [] num = 0 while x!=0 or y!=0: res.append((x%2, y%2)) x = x // 2 y = y // 2
        for i in res: if i[0] != i[1]: num += 1
        return num

但是這樣比較慢,可以直接先異或,再統計1的個數

class Solution: def hammingDistance(self, x: int, y: int) -> int: """ 首先將兩個數字都轉換為2進制數字存儲為列表,之后找出來不一樣的項的個數 或者直接進行異或運算,計算結果里面1的個數即可 """
        return bin(x ^ y).count('1')

統計1的個數函數已經封裝好了,但是也可以自己寫,比較簡單,判斷該二進制最后一位是不是1,然后右移一位,再判斷,再右移,直到二進制數為0。

class Solution: def hammingDistance(self, x: int, y: int) -> int: """ 首先將兩個數字都轉換為2進制數字存儲為列表,之后找出來不一樣的項的個數 或者直接進行異或運算,計算結果里面1的個數即可 """ z = x ^ y num = 0 while z!=0: if z & 1 == 1: num += 1 z = z >> 1
        return num

后面兩種方法一樣快,第一種方法最慢,應該是運算次數比較多的緣故吧。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM