给定一个整数数组 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冲突)
给定一个只包括 ‘(’,’)’,’{’,’}’,’[’,’]’ 的字符串 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
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
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
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
给定一个整数数组 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;
}
}
假设你正在爬楼梯。需要 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)
给定一个二叉树,检查它是否是镜像对称的。
例如,二叉树 [1,2,2,3,4,4,3] 是对称的。
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);
}
}
给定一个二叉树,找出其最大深度。
二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
说明: 叶子节点是指没有子节点的节点。
'''
# 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)
给定一个数组 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
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
说明:你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
示例 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)
编写一个程序,找到两个单链表相交的起始节点。
示例 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
给定一个大小为 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)
给你单链表的头节点 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
借助外部空间的解法
由于题目并没有要求必须原地反转,因此可以借助外部空间实现。这里可以将单链表储存为数组,然后按照数组的索引逆序进行反转。但是,此方式比较浪费空间,而且需要两次遍历,效率不占优势。
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;
}
给定一个数组 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);
}
}
给定一个非负整数 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;
}
}
给你一个含 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);
}
}