【Leetcode】新手tag刷题笔记-算法简单题

tag分类顺序刷题-算法简单题-python/Java

  • 1. 两数之和
  • 20. 有效的括号
  • 21. 合并两个有序链表
  • 53. 最大子序和
  • 70. 爬楼梯
  • 101. 对称二叉树
  • 104. 二叉树的最大深度
  • 121. 买卖股票的最佳时机
  • 136. 只出现一次的数字
  • 160. 相交链表
  • 169. 多数元素
  • 206.反转链表
    • JAVA语言
  • 283. 移动零
  • 338. 比特位计数
  • 448. 找到所有数组中消失的数字

1. 两数之和

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。

# 方法一
nums = [3,2,4];
print("输入的列表是:",nums);
targe = 6;
print("输入的targe是:",targe);
for i in range(0,3):
    for j in range(i+1,3):
        if (targe == nums[i] + nums[j]):
            print("[%s,%s]"%(i,j));
# 方法二哈希表
class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:
        hashtable = dict()
        for i, num in enumerate(nums):
            if target - num in hashtable:
                return [hashtable[target - num], i]
            hashtable[nums[i]] = i
        return []
# 两数之和(twosum)
class Solution(object):
    def twoSum(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[int]
        """
        map_a = dict()
        k = len(nums)
        for i in range(0, k):#一边将列表中的数添加到字典中,一边判断两数之差是否存在于字典中
            temp = target - nums[i]  
            if temp in map_a :  # 判断步骤
                return [map_a[temp], i]
            map_a[nums[i]] =  i  # 添加步骤(切记先判断再添加,以免key冲突)

20. 有效的括号

给定一个只包括 ‘(’,’)’,’{’,’}’,’[’,’]’ 的字符串 s ,判断字符串是否有效。

有效字符串需满足:

左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。

# 方法一:使用栈,枚举
class Solution:
    def isValid(self, s: str) -> bool:
        n = len(s)
        if n == 0:
            return True
        stack = []
        for i in s:
            if i == '(' or i == '[' or i == '{':
                stack.append(i)
            else:
                if len(stack) == 0:
                    return False
                else:
                    temp = stack.pop()
                    if i == ')':
                        if temp != '(':
                            return False
                    elif i == '[':
                        if temp != ']':
                            return False
                    elif i == '}':
                        if temp != '{':
                            return False
        if len(stack) == 0:
            return True
        else:
            return False

【Leetcode】新手tag刷题笔记-算法简单题_第1张图片

not stack 指空栈

stack[-1] 指栈顶

# 方法二:使用栈,字典
class Solution:
    def isValid(self, s: str) -> bool:
        if len(s) % 2 == 1:# 如果是单数,则False
            return False
        # 建立一个字典,根据右括号来查找左括号
        pairs = {
            ")": "(",
            "]": "[",
            "}": "{",
        }
        stack = list()# 建立一个栈
        for ch in s:
            if ch in pairs:
                if not stack or stack[-1] != pairs[ch]:# 如果是空栈或者栈顶不等于左括号
                    return False
                stack.pop()
            else:
                stack.append(ch)
        
        return not stack

21. 合并两个有序链表

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

val()函数语法为:

i. val(字符表达式)

val()函数的功能为:将一组字符型数据的数字部分转换成相应的数值型数据
val()函数用法:

# 这是个有序数列
class Solution:
    def mergeTwoLists(self, l1:list, l2:list)->list:
        if not l1:
            return l2
        if not l2:
            return l1
        if l1.val <= l2.val:# 取其中一个数
            l1.next = self.mergeTwoLists(l1.next,l2)
            return l1
        else:
            l2.next = self.mergeTwoLists(l1,l2.next)
            return l2

53. 最大子序和

给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。

# 方法一暴力解法
nums = list(map(int,input().split()))
n = len(nums)
tmp = nums[0]
ans = tmp
for i in range(0, n):
    sum = 0
    for j in range(i, n):
        sum += nums[j]
        if sum > ans:
            ans = sum
print(ans)

JAVA
这道题用动态规划的思路并不难解决,比较难的是后文提出的用分治法求解,但由于其不是最优解法,所以先不列出来
动态规划的是首先对数组进行遍历,当前最大连续子序列和为 sum,结果为 ans
如果 sum > 0,则说明 sum 对结果有增益效果,则 sum 保留并加上当前遍历数字
如果 sum <= 0,则说明 sum 对结果无增益效果,需要舍弃,则 sum 直接更新为当前遍历数字

每次比较 sum 和 ans的大小,将最大值置为ans,遍历结束返回结果

# 方法二:JAVA,动态规划
class Solution {
    public int maxSubArray(int[] nums) {
        int ans = nums[0];
        int sum = 0;
        for(int num: nums) {
            if(sum > 0) {
                sum += num;
            } else {
                sum = num;
            }
            ans = Math.max(ans, sum);
        }
        return ans;
    }
}

70. 爬楼梯

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?

注意:给定 n 是一个正整数。

# 法一:费婆那契数列
class Solution:
    def climbStairs(self, n: int) -> int:
        a = 1
        b = 1
        if n == 1:
            return n
        elif n == 2:
            return n
        else:
            for i in range(2,n+1):
                a,b = b,a+b
            return b
# 法二:递归
class Solution:
    def climbStairsMemo(self, n: int, memo: List[int]) -> int:
        if memo[n] > 0:
            return memo[n]
        if n == 1:
            memo[n] = 1
        elif n == 2:
            memo[n] = 2
        else:
            memo[n] = self.climbStairsMemo(n - 1, memo) + self.climbStairsMemo(n - 2, memo)
        return memo[n]

    def climbStairs(self, n: int) -> int:
        memo = [0 for i in range(n + 1)]
        return self.climbStairsMemo(n, memo)

101. 对称二叉树

给定一个二叉树,检查它是否是镜像对称的。

例如,二叉树 [1,2,2,3,4,4,3] 是对称的。

【Leetcode】新手tag刷题笔记-算法简单题_第2张图片

class Solution:
    def isSymmetric(self, root: TreeNode) -> bool:
        if not root:# 如果根为空,则返回ture
            return True
        def dfs(left,right):
            if not (left or right):# 如果left和right都为空,则返回ture
                return True
            if not (left and right):# 如果如果left和right有一个不为空,则返回False
                return False
            if left.val != right.val:# 如果如果left和right不相等,则返回False
                return False
            return dfs(left.left,right.right) and dfs(left.right,right.left)
        return dfs(root.left,root.right)# 用递归函数,比较左节点,右节点

JAVA

class Solution {
	public boolean isSymmetric(TreeNode root) {
		if(root==null) {
			return true;
		}
		//调用递归函数,比较左节点,右节点
		return dfs(root.left,root.right);
	}
	
	boolean dfs(TreeNode left, TreeNode right) {
		//递归的终止条件是两个节点都为空
		//或者两个节点中有一个为空
		//或者两个节点的值不相等
		if(left==null && right==null) {
			return true;
		}
		if(left==null || right==null) {
			return false;
		}
		if(left.val!=right.val) {
			return false;
		}
		//再递归的比较 左节点的左孩子 和 右节点的右孩子
		//以及比较  左节点的右孩子 和 右节点的左孩子
		return dfs(left.left,right.right) && dfs(left.right,right.left);
	}
}

104. 二叉树的最大深度

给定一个二叉树,找出其最大深度。

二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。

说明: 叶子节点是指没有子节点的节点。

【Leetcode】新手tag刷题笔记-算法简单题_第3张图片

'''
# def PreOrder(self, root):
#     '''打印二叉树(前序遍历)根—左—右'''
#     if root == None:
#         return
#     print(root.val, end=' ')
#     self.PreOrder(root.left)
#     self.PreOrder(root.right)
#
# List1 = [1,[2,[4,[8],[9]],[5]],[3,[6],[7]]]
# op = PreOrder(List1)


class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

class Solution:
    def create(self, List):
        '''二叉搜索树插入操作'''
        root = TreeNode(List[0])
        lens = len(List)
        if lens >= 2:
            root.left = self.create(List[1])
        if lens >= 3:
            root.right = self.create(List[2])
        return root

    def maxDepth(self, root: TreeNode) -> int:
        if not root:
            return 0
        left = self.maxDepth(root.left)
        right = self.maxDepth(root.right)
        return max(left,right) + 1

if __name__ == '__main__':
    List1 = [1,[2,[4,[8],[9]],[5]],[3,[6],[7]]]
    List2 = [3,[9,[None],[None]],[20,[15],[7]]]
    op = Solution()
    tree = op.create(List2)
    t = op.maxDepth(tree)
    print(t)

121. 买卖股票的最佳时机

给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。

你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。

返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。

示例 1:

输入:[7,1,5,3,6,4]
输出:5
解释:在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。
示例 2:

输入:prices = [7,6,4,3,1]
输出:0
解释:在这种情况下, 没有交易完成, 所以最大利润为 0。

# 发一 官方
class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        inf = int(1e9)
        minprice = inf
        maxprofit = 0
        for price in prices:
            maxprofit = max(price - minprice, maxprofit)
            minprice = min(price, minprice)
        return maxprofit
# 法二 超时
class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        n = len(prices)
        sum = 0
        a = 0

        for i in range(0,n):
            for j in range(i+1,n):
                t = prices[j] - prices[i]
                if t > sum:# 不是[7,6,4,3,1]
                    a = 1
                    sum = t
                j += 1
            i += 1
        if not a:# 是0
            return 0
        else:
            return sum

136. 只出现一次的数字

给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
说明:你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
示例 1:
输入: [2,2,1]
输出: 1
示例 2:
输入: [4,1,2,1,2]
输出: 4

# 法一 排序 暴力解题
class Solution:
    def singleNumber(self, nums: List[int]) -> int:
        n = len(nums)
        nums.sort()
        for i in range(0,n,2):
            if i+1 == n:
                return nums[i]
                break
            elif nums[i] != nums[i+1]:
                return nums[i]
                break

对于这道题,可使用异或运算 \oplus⊕。异或运算有以下三个性质。

任何数和 0 做异或运算,结果仍然是原来的数,即 a⊕0=a。
任何数和其自身做异或运算,结果是 0,即 a⊕a=0。
异或运算满足交换律和结合律,即 a⊕b⊕a=b⊕a⊕a=b⊕(a⊕a)=b⊕0=b。

reduce函数

ambda函数

链接: https://blog.csdn.net/m0_37882192/article/details/115220493.

# 法二 位运算
class Solution:
    def singleNumber(self, nums: List[int]) -> int:
        return reduce(lambda x, y: x ^ y, nums)

160. 相交链表

编写一个程序,找到两个单链表相交的起始节点。
示例 1:
输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
输出:Reference of the node with value = 8
输入解释:相交节点的值为 8 (注意,如果两个链表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。
在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。

# Definition for singly-linked list.
class ListNode:
    def __init__(self, x):
        self.val = x
        self.next = None
# hash表算法
class Solution(object):
    def getIntersectionNode(self, headA: ListNode, headB: ListNode):
        """
        :type head1, head1: ListNode
        :rtype: ListNode
        """
        if headA is None or headB is None:  # 先判断链表A和链表B是否为空
            return None
        cur1 = headA
        cur2 = headB
        hashmap = set()  # 创建哈希表
        while cur1:
            hashmap.add(cur1)  # headA中的每个节点存储到哈希表中
            cur1 = cur1.next
        while cur2:
            if cur2 in hashmap:  # 判断当前cur2这个节点是否存在于hashmap中,是他即为相交节点
                return cur2
            cur2 = cur2.next

nums1 = [4,1,8,4,5]
nums2 = [5,0,1,8,4,5]
op = Solution()
shu = op.getIntersectionNode(nums1,nums2)
print(shu)

# 双指针算法
# class Solution(object):
#     def getIntersectionNode(self, headA: ListNode, headB: ListNode):
#         head1 = headA
#         head2 = headB
#         while(head1 != head2):
#             if head1:
#                 head1 = head1.next
#             else:
#                 head1 = headB #
#             if head2:
#                 head2 = head2.next
#             else:
#                 head2 = headA
#         return head1

# class Solution(object):
#     def getIntersectionNode(self, headA, headB):
#         p1 = headA
#         p2 = headB
#         while(p1 != p2):
#             p1 = headB if p1 == None else p1.next
#             p2 = headA if p2 == None else p2.next
#         return p1

169. 多数元素

给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。
你可以假设数组是非空的,并且给定的数组总是存在多数元素。
示例 1:输入:[3,2,3]输出:3
示例 2:输入:[2,2,1,1,1,2,2]输出:2

from typing import List
# 方法一:排序法
# class Solution:
#     def majorityElement(self, nums: List[int]) -> int:
#         nums.sort() # 从小向大排列
#         n = len(nums)
#         # print(nums)
#         # print(n//2)
#         return nums[n//2]

# 法二:hash表
from collections import defaultdict
class Solution:
    def majorityElement(self, nums: List[int]) -> int:
        dic = defaultdict(int)
        #统计每个数字出现的次数
        for num in nums:
            dic[num] += 1
        #返回出现次数最多的num, 即返回字典中最大value对应的key
        return max(dic, key=dic.get)

list1 = [2,2,1,1,1,2,2]
p = Solution()
cur = p.majorityElement(list1)
print(cur)

206.反转链表

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。
示例 1:输入:head = [1,2,3,4,5]
输出:[5,4,3,2,1]

# 双指针算法
class Solution:
    def reverseList(self, head: ListNode) -> ListNode:
        # 定义两个变量,分别为空链表和链表head
        pre = None
        cur = head
        # 进行循环遍历,双指针
        while(cur):
            # sef.next是指向下一个节点的索引
            # 先把cur.next指向的值赋给temp
            temp = cur.next
            # 再把cur.next指向pre
            cur.next = pre
            # 在分别把pre和cur向前移动一位
            pre = cur
            cur = temp
        return pre

JAVA语言

借助外部空间的解法

由于题目并没有要求必须原地反转,因此可以借助外部空间实现。这里可以将单链表储存为数组,然后按照数组的索引逆序进行反转。但是,此方式比较浪费空间,而且需要两次遍历,效率不占优势。

public static Node ReverseList1(Node head)
    {
        if(head == null)
        {
            return null;
        }

        List<Node> nodeList = new List<Node>();
        while (head != null)
        {
            nodeList.Add(head);
            head = head.Next;
        }

        int startIndex = nodeList.Count - 1;
        for (int i = startIndex; i >= 0; i--)
        {
            Node node = nodeList[i];
            if (i == 0)
            {
                node.Next = null;
            }
            else
            {
                node.Next = nodeList[i - 1];
            }
        }
        // 现在头结点是原来的尾节点
        head = nodeList[startIndex];
        return head;
    }

283. 移动零

给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
示例:
输入: [0,1,0,3,12]
输出: [1,3,12,0,0]

# # 方法一:使用了额外的数组
# class Solution:
#     def moveZeroes(self, nums: List[int]) -> None:
#         j = 0
#         nums1 = []
#         # nums.sort()
#         for i in nums:
#             if i != 0:
#                 nums1.append(i)
#             else:
#                 j = j+1
#         if j == 0:
#             print(nums1)
#         else:
#             for k in range(0,j):
#                 nums1.append("0")
#
#             print(nums1)
#
# list1 = [0,1,0,3,12]
# t = Solution()
# print(t.moveZeroes(list1))



# 方法二:双指针
class Solution:
    def moveZeroes(self, nums: List[int]) -> None:
        n = len(nums)
        left = right = 0
        while right < n:
            if nums[right] != 0:
                nums[left], nums[right] = nums[right], nums[left]
                left += 1
            right += 1

Java方法

/**
 283. 移动零
 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
 示例:
 输入: [0,1,0,3,12]
 输出: [1,3,12,0,0]
 */

public class MoveZeroes {
    public static void moveZeroes(int[] nums) {

        // 法一,暴力解法
//        if (nums == null || nums.length == 0) {
//            return;
//        }
//        int[] tmp = new int[nums.length];
//        int j = 0;
//        for (int i = 0; i < nums.length; i++) {
//            if (nums[i] != 0) {
//                tmp[j] = nums[i];
//                j++;
//            }
//        }
//        for (int i = 0; i < nums.length; i++) {
//            nums[i] = tmp[i];
//
//        }
//        System.out.println(Arrays.toString(nums));
//    }
//##########################################

        //法二,双指针
        int n = nums.length;
        int l = 0, r = 0;
        while (r<n){
            if(nums[r] != 0){
                swap(nums, l, r);
                l++;
            }
            r++;
        }
        System.out.println(Arrays.toString(nums));
    }
    public static void swap(int[] nums, int l, int r) {
        int temp = nums[l];
        nums[l] = nums[r];
        nums[r] = temp;
    }

    public static void main(String[] args){
//        List list1 = new ArrayList();
        int[] list1 = {0, 1, 0, 3, 12};
        moveZeroes(list1);
    }
}

338. 比特位计数

给定一个非负整数 num。对于 0 ≤ i ≤ num 范围中的每个数字 i ,计算其二进制数中的 1 的数目并将它们作为数组返回。

package CodePackage;
/**
 338. 比特位计数
 给定一个非负整数 num。对于 0 ≤ i ≤ num 范围中的每个数字 i ,
 计算其二进制数中的 1 的数目并将它们作为数组返回。
 示例 1:输入: 2,输出: [0,1,1]
 示例 2:输入: 5,输出: [0,1,1,2,1,2]
 */

public class CountBits {
    public int[] countBits(int n) {
        int[] result = new int[n+1];
//        vector result(num+1);
        result[0] = 0;
        for(int i = 1; i <= n; i++)
        {
            if(i % 2 == 1)  //奇数:二进制表示中,奇数一定比前面那个偶数多一个 1,因为多的就是最低位的 1。
            {
                result[i] = result[i-1] + 1;
            }
//偶数:二进制表示中,偶数中 1 的个数一定和除以 2 之后的那个数一样多。
// 因为最低位是 0,除以 2 就是右移一位,也就是把那个 0 抹掉而已,所以 1 的个数是不变的。
            else
            {
                result[i] = result[i/2];
            }
        }
        return result;

    }
}

448. 找到所有数组中消失的数字

给你一个含 n 个整数的数组 nums ,其中 nums[i] 在区间 [1, n] 内。请你找出所有在 [1, n] 范围内但没有出现在 nums 中的数字,并以数组的形式返回结果。

package CodePackage;
/**
 448. 找到所有数组中消失的数字
 给你一个含 n 个整数的数组 nums ,其中 nums[i] 在区间 [1, n] 内。
 请你找出所有在 [1, n] 范围内但没有出现在 nums 中的数字,并以数组的形式返回结果。
 示例 1:输入:nums = [4,3,2,7,8,2,3,1],输出:[5,6]
 示例 2:输入:nums = [1,1],输出:[2]
 */
import java.util.ArrayList;
import java.util.*;
public class FindDisappearedNumbers {
    public List<Integer> findDisappearedNumbers(int[] nums) {
        int n = nums.length;
        for(int num : nums){
            //当我们遍历到某个位置时,其中的数可能已经被增加过,因此需要对 nn 取模来还原出它本来的值
            int x = (num - 1) % n;
            nums[x] += n;
        }
        List<Integer> val = new ArrayList<Integer>();
        for(int i=0; i < n; i++){
            if(nums[i] <= n){
                val.add(i+1);
            }
        }
        return val;
    }
    public static void main(String[] args) {
        //定义数组
        int[] list1 = {4, 3, 2, 7, 8, 2, 3, 1};
        //调用方法
        FindDisappearedNumbers t = new FindDisappearedNumbers();
        //需要指明方法的数据类型List
        List<Integer> list = t.findDisappearedNumbers(list1);
        System.out.println(list);
    }
}

你可能感兴趣的:(编程练习题,leetcode)