算法设计(二)

1.

给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

示例:

输入: [-2,1,-3,4,-1,2,1,-5,4],
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。

进阶:

如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的分治法求解:

public class Solution {
public int MaxSubArray(int[] nums) 
{
  int res = nums[0];
  int sum = nums[0];
  for(int i = 1; i < nums.Length; i++)
  { 
    sum = Math.Max(nums[i], sum + nums[i]);
    res = Math.Max(res, sum);
  }
  return res;
  }
}

 

2.

给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。

你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。

示例:

给定 nums = [2, 7, 11, 15], target = 9

因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]

复杂度分析:

  • 时间复杂度:O(n)O(n), 我们只遍历了包含有 nn 个元素的列表一次。在表中进行的每次查找只花费 O(1)O(1) 的时间。

  • 空间复杂度:O(n)O(n), 所需的额外空间取决于哈希表中存储的元素数量,该表最多需要存储 nn 个元素。

事实证明,我们可以一次完成。在进行迭代并将元素插入到表中的同时,我们还会回过头来检查表中是否已经存在当前元素所对应的目标元素。如果它存在,那我们已经找到了对应解,并立即将其返回。

 public int[] twoSum(int[] nums, int target) {

  Map<Integer, Integer> map = new HashMap<>();
  for (int i = 0; i < nums.length; i++) {
    int complement = target - nums[i];
    if (map.containsKey(complement))

      {

      return new int[] { map.get(complement), i };

     }
    map.put(nums[i], i);
    }
    throw new IllegalArgumentException("No two sum solution");
}

 

3.两数相加

给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。

如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。

您可以假设除了数字 0 之外,这两个数都不会以 0 开头。

示例:

输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807

算法

就像你在纸上计算两个数字的和那样,我们首先从最低有效位也就是列表 l1l1 和 l2l2 的表头开始相加。由于每位数字都应当处于 0 \ldots 909 的范围内,我们计算两个数字的和时可能会出现“溢出”。例如,5 + 7 = 125+7=12。在这种情况下,我们会将当前位的数值设置为 22,并将进位 carry = 1carry=1 带入下一次迭代。进位 carrycarry 必定是 00 或 11,这是因为两个数字相加(考虑到进位)可能出现的最大和为 9 + 9 + 1 = 199+9+1=19。

伪代码如下:

  • 将当前结点初始化为返回列表的哑结点。
  • 将进位 carrycarry 初始化为 00。
  • 将 pp 和 qq 分别初始化为列表 l1l1 和 l2l2 的头部。
  • 遍历列表 l1l1 和 l2l2 直至到达它们的尾端。
    • 将 xx 设为结点 pp 的值。如果 pp 已经到达 l1l1 的末尾,则将其值设置为 00。
    • 将 yy 设为结点 qq 的值。如果 qq 已经到达 l2l2 的末尾,则将其值设置为 00。
    • 设定 sum = x + y + carrysum=x+y+carry。
    • 更新进位的值,carry = sum / 10carry=sum/10。
    • 创建一个数值为 (sum \bmod 10)(summod10) 的新结点,并将其设置为当前结点的下一个结点,然后将当前结点前进到下一个结点。
    • 同时,将 pp 和 qq 前进到下一个结点。
  • 检查 carry = 1carry=1 是否成立,如果成立,则向返回列表追加一个含有数字 11 的新结点。
  • 返回哑结点的下一个结点。

请注意,我们使用哑结点来简化代码。如果没有哑结点,则必须编写额外的条件语句来初始化表头的值。

复杂度分析

  • 时间复杂度:O(\max(m, n))O(max(m,n)),假设 mm 和 nn 分别表示 l1l1 和 l2l2 的长度,上面的算法最多重复 \max(m, n)max(m,n) 次。

  • 空间复杂度:O(\max(m, n))O(max(m,n)), 新列表的长度最多为 \max(m,n) + 1max(m,n)+1。

 1  // Definition for singly-linked list.
 2   public class ListNode {
 3       public int val;
 4       public ListNode next;
 5       public ListNode(int x) { val = x; }
 6   }
 7  
 8 public class Solution {
 9     public ListNode AddTwoNumbers(ListNode l1, ListNode l2) 
10     {
11         ListNode node1 = l1.next;
12         ListNode node2 = l2.next;
13         int arry = 0;  
14         ListNode newNode = new ListNode(0);
15         while(node1 !=null || node2 != null)
16         {
17             int x = node1 != null ? node1.val:0;
18             int y = node2 != null ? node2.val:0;
19             int sum = x + y + arry;
20             arry = sum / 10;
21             newNode.next = new ListNode(sum % 10);
22             newNode = newNode.next;
23             
24             node1 = (node1!=null)? node1.next:null;
25             
26             node2 = (node2!=null)? node2.next:null;   
27         }
28        
29         if(arry > 0)
30             newNode.next = new ListNode(arry);
31         
32         return newNode;
33     }
34 }
View Code

 4.无重复字符的最长字串

给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。

示例 1:

输入: "abcabcbb"
输出: 3 
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。

示例 2:

输入: "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。

示例 3:

输入: "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
     请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
 1 public class Solution {
 2     public int LengthOfLongestSubstring(string s) {
 3         int[] map = new int[128];
 4         int left = 0, right = 0, cnt = 0;
 5         while (right < s.Length){
 6             int c = (int)(s[right]);
 7             if (map[c] == 0){
 8                 map[c] = 1;
 9                 right++;
10             } else {
11                 map[(int)(s[left])] = 0;
12                 left++;
13             }
14             if (right - left > cnt) cnt = right - left;
15         }
16         return cnt;
17     }
18 }
View Code

 

posted @ 2019-04-18 16:49  GamesClient  阅读(136)  评论(0编辑  收藏  举报