算法面试题目

1.斐波那契三角形

# 斐波那契三角形
# [1]
# [1, 1, 1]
# [1, 1, 2, 1, 1]
# [1, 1, 2, 3, 2, 1, 1]
# [1, 1, 2, 3, 5, 3, 2, 1, 1]
# [1, 1, 2, 3, 5, 8, 5, 3, 2, 1, 1]
# [1, 1, 2, 3, 5, 8, 13, 8, 5, 3, 2, 1, 1]
def fib(n):
    if n == 1:
        return 1
    if n == 2:
        return 1
    if n > 2:
        return fib(n - 1) + fib(n - 2)


def listfib(n):
    alist = []
    for i in range(1, n + 1):
        alist.append(fib(i))
    return alist


def fib_three(n):
    for i in range(1, n + 1):
        if i <= 1:
            print(listfib(i))
        else:
            print(listfib(i) + listfib(i)[0:i - 1][::-1])

fib_three(7)

2.两数之和,链表相加,不含重复字符的最长子串

# 题目:
#
# 给定一个整数数列,找出其中和为特定值的那两个数。
#
# 你可以假设每个输入都只会有一种答案,同样的元素不能被重用。
#
# 示例:
#
# 给定 nums = [2, 7, 11, 15], target = 9
#
# 因为 nums[0] + nums[1] = 2 + 7 = 9
# 所以返回 [0, 1]
def twoSum1(nums, target):
    hashmap = {}
    for index, num in enumerate(nums):
        another_num = target - num
        if another_num in hashmap:
            return [hashmap[another_num], index]
        else:
            hashmap[num] = index
    return None


alist = [2, 7, 11, 15]
print(twoSum1(alist, 18))


# 链表(linked list)是由一组被称为结点的数据元素组成的数据结构,每个结点都包含结点本身的信息和指向下一个结点的地址。
# 由于每个结点都包含了可以链接起来的地址信息,所以用一个变量就能够访问整个结点序列。也就是说,
# 结点包含两部分信息:一部分用于存储数据元素的值,称为信息域;另一部分用于存储下一个数据元素地址的指针,称为指针域。
# 链表中的第一个结点的地址存储在一个单独的结点中,称为头结点或首结点。链表中的最后一个结点没有后继元素,其指针域为空。
# 给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照逆序的方式存储的,并且它们的每个节点只能存储 一位 数字。
# 如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。您可以假设除了数字 0 之外,这两个数都不会以 0 开头。
# 输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
# 输出:7 -> 0 -> 8
# 原因:342 + 465 = 807

# Definition for singly-linked list.
class ListNode:
    def __init__(self, x):
        self.val = x
        self.next = None
    # 你可以实现一些链表的增删等操作


# 初始化创建一个ListNode(0),next指向求和后的结果
class Solution:
    def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
        result = ListNode(0)  # result是一个头指针,将其数据初始化为了0
        r = result  # r总是指向返回结果的链表的新元素
        carry = 0  # carry表示进位

        # 循环进行对应位相加
        while (l1 or l2):
            x = (l1.val if l1 else 0)  # 如果l1有数据,则x为该数据,否则为0
            y = (l2.val if l2 else 0)  # 如果l2有数据,则y为该数据,否则为0
            s = carry + x + y

            carry = s // 10  # 得到进位(0或1)
            r.next = ListNode(s % 10)  # 新建一个节点,并保存该位的运算结果
            r = r.next  # r与r.next将指向同一个内存地址

            # 将“指针”向后移动
            if l1 != None:
                l1 = l1.next
            if l2 != None:
                l2 = l2.next

        # 判断最高位相加后是否有进位,有进位则新建一个节点保存进位‘1’
        if (carry > 0):
            r.next = ListNode(1)

        return result.next  # 注意:这里返回的是result.next,而不是result。因为result是头指针,没有真正保存有效的数据
#个人理解

def add_num(l1, l2):
    first_node = ListNode(0)  # 创建一个初始节点为0
    cur = first_node  # 创建一个指针指向当前节点,初始化时指向first_node
    jinwei = 0  # 相加后超过10的进位
    while l1 or l2:
        # 获取到初始节点的值
        num1 = l1.val if l1 else 0
        num2 = l2.val if l2 else 0
        # 每一个位上的和为对应值加上前一位进位
        sum_num = num1 + num2 + jinwei
        # 进位为和除以10的商
        jinwei = sum_num // 10
        # 余数为当前节点的下一个节点
        cur.next = ListNode(sum_num % 10)
        # 重置l1,l2,cur,进行下轮循环
        l1 = l1.next if l1 else None
        l2 = l2.next if l2 else None
        cur = cur.next
    # 循环完成后最高位如果还有进位
    if jinwei > 0:
        cur.next = ListNode(jinwei)
    #     返回值为第一个节点0的下一个节点
    return first_node.next

num1 = ListNode(2)
num1.next = ListNode(4)
num1.next.next = ListNode(3)

num2 = ListNode(5)
num2.next = ListNode(6)
num2.next.next = ListNode(4)

solution = Solution()
result = solution.addTwoNumbers(num1, num2)
print(result.val, result.next.val, result.next.next.val)


# 假设一个不存在重复元素的正序数组,但是数组在某个未知的位置进行了旋转,例如
# [1,2,3,4,5,6,7,8,9]旋转后为[4,5,6,7,8,9,1,2,3]
# 搜索给定数值在数组中的索引,不存在返回-1,时间复杂度o(log n)级别
def find_index(alist, target):
    left_index = 0
    right_index = len(alist) - 1
    if target == alist[left_index]:
        return 0
    if target == alist[right_index]:
        return len(alist) - 1
    for i in range(len(alist)):
        if target > alist[left_index]:
            left_index += 1
        if target == alist[left_index]:
            return left_index
        if target <= alist[right_index]:
            right_index -= 1
        if target == alist[right_index]:
            return right_index
    else:
        return -1


alist = [4, 5, 6, 7, 8, 9, 1, 2, 3]
print(find_index(alist, 1))

# 给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度
# 思路:定义一个变量指向最长子串的起始位置,定义一个变量表示最长子串长度,定义一个字典存放不重复的元素及其下标
def lengthOfLongestSubstring(s):
    """
    :type s: str
    :rtype: int
    """
    start = 0
    usedChar = {}  # 记录每个元素和它最后一次出现位置
    max_len = 0  # 记录最长子串长度
    for i in range(len(s)):
        # 如果第i个元素在字典中并且第i个元素在表中索引大于等于start,
        if s[i] in usedChar and usedChar[s[i]] >= start:
            start = usedChar[s[i]] + 1
        # 如果第i个元素不在字典中
        else:
            max_len = max(max_len, i - start + 1)  # 最长子串长度取之前最长的长度和
        usedChar[s[i]] = i  # 1.如果没有在字典中,将第i元素加入到字典中2.如果已经在字典中了,就更改value值
    return max_len


print(lengthOfLongestSubstring("a123456"))

3.寻找数组中心索引

# 寻找数组的中心索引
# 给定一个整数类型的数组 nums,请编写一个能够返回数组“中心索引”的方法。
#
# 我们是这样定义数组中心索引的:数组中心索引的左侧所有元素相加的和等于右侧所有元素相加的和。
#
# 如果数组不存在中心索引,那么我们应该返回 -1。如果数组有多个中心索引,那么我们应该返回最靠近左边的那一个。
# 输入:
# nums = [1, 7, 3, 6, 5, 6]
# 输出: 3
# 解释:
# 索引3 (nums[3] = 6) 的左侧数之和(1 + 7 + 3 = 11),与右侧数之和(5 + 6 = 11)相等。
# 同时, 3 也是第一个符合要求的中心索引。
# 以 [1, 7, 3, 6, 5, 6] 为例,6 为中心索引为 i 的元素 j,左侧和 left_sum 为 11,右侧和 right_sum 也为 11。
#
# 所以可以将数组表示为 [left_sum, j, right_sum] ,而且left_sum = right_sum ,设数组所有元素和为 total ,
# 则有式子 2*left_sum + j = total 成立,以此条件判断是否为中心索引。
def find_center_index(nums):
    sum_nums = sum(nums)
    left_sum = 0
    for i, j in enumerate(nums):
        if 2 * left_sum + j == sum_nums:
            return i
        left_sum += j
    return -1
nums = [1, 7, 3, 6, 5, 6]
print(find_center_index(nums))
nums = [i for i in range(100)]
import random
random.shuffle(nums)
print(nums)
print(find_center_index(nums))

4.约瑟夫问题

#!usr/bin/python
# -*- coding: utf-8 -*-
# 约瑟夫斯问题(Josephus Problem)是应用队列(确切地说,是循环队列)的典型案例。在 约瑟夫斯问题 中,参与者围成一个圆圈,从某个
# 人(队首)开始报数,报数到n+1的人退出圆圈,然后从退出人的下一位重新开始报数;重复以上动作,直到只剩下一个人为止。
# 思路:使用队列先进先出特性,将报的n个数的人从队列中删除,然后添加到对尾,此时第一个人就是第一次计数后将要退出的人,将它退出,第一轮结束
# 此后每轮都依次进行即可
class Queue:
    def __init__(self):
        self.items = []

    def enqueue(self, item):
        self.items.append(item)

    def dequeue(self):
        return self.items.pop(0)

    def empty(self):
        return self.size() == 0

    def size(self):
        return len(self.items)


def printquene(queue):
    for i in queue.items:
        print(i, end=",")


def josephus(namelist, num):
    simqueue = Queue()

    for name in namelist:
        simqueue.enqueue(name)

    while simqueue.size() > 1:
        for i in range(num):
            simqueue.enqueue(simqueue.dequeue())
        printquene(simqueue)
        print()
        simqueue.dequeue()

    return simqueue.dequeue()


if __name__ == '__main__':
    print(josephus(["Bill", "David", "Kent", "Jane", "Susan", "Brad","java"], 3))


# Jane,Susan,Brad,Bill,David,Kent,
# David,Kent,Susan,Brad,Bill,
# Bill,Kent,Susan,Brad,
# Kent,Susan,Brad,
# Brad,Susan,
# Susan

5.

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值