`

大公司面试算法题 - 第二题

阅读更多
昨天发了第一题,今天发第二题。这个题目在一个网络竞赛中有,当时因为时间没做出来,没想到面试又遇到了。

看来平时对问题的深入钻研还是非常有用的。我当时要在赛后再好好钻研一下,没准就面试通过了。

下面看题目:




给一个整数数组A={a1,a2,…an}, 将这个数组首尾相接连成一个环状,它的一个子序列是指这个数组连续的一段,比如a2,a3…ak,或者an,a1…ai。请从这个环上选取两个不重叠的非空子序列,使这两个子序列中的所有数字之和最大。

例如: 1,-1,1,0 结果为2

1,-3,-1,2,-1 结果为2


下面是解题代码,Base类的代码在上一篇博客中可以找到:


import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;

/**
* <pre>
* 给一个整数数组A={a1,a2,…an}, 将这个数组首尾相接连成一个环状,它的一个子序列是指这个数组连续的一段,比如a2,a3…ak,或者an,a1…ai。请从这个环上选取两个不重叠的非空子序列,使这两个子序列中的所有数字之和最大。
* 例如:
* 1,-1,1,0 结果为2
* 1,-3,-1,2,-1 结果为2
* </pre>
*
* @author chouy
*/
public class Interview2 extends Base
{
    private int maxSum = 0;

    public int getMaxSum()
    {
        return maxSum;
    }

    public void maxSubSequence(int[] array)
    {
        maxSum = array[0];
        debug(Arrays.toString(array));
        List<Integer> list = continousNumMerge(array);
        this.setMax(list);
        debug(list.toString());
        int loop = 1;
        while (list.size() >= 3)
        {
            int oldSize = list.size();
            debug("-------------- loop " + loop++ + " list.size=" + list.size() + " --------------");
            nearMerge(list);
            this.setMax(list);
            if (oldSize == list.size())
                break;
        }
        debug(list.toString());
    }

    /**
     * 合并相同符号的连续的数字
     *
     * @param array
     * @return
     */
    private LinkedList<Integer> continousNumMerge(int[] array)
    {
        LinkedList<Integer> list = new LinkedList<Integer>();
        boolean lastValueIsPlus = array[0] > 0;
        int v = array[0];
        for (int pos = 1; pos < array.length; pos++)
        {
            if (array[pos] > this.maxSum)
                this.maxSum = array[pos];
            if (array[pos] == 0)
                continue;
            if (lastValueIsPlus)
            {
                if (array[pos] > 0)
                {
                    v += array[pos];
                    continue;
                }
            }
            else
            {
                if (array[pos] < 0)
                {
                    v += array[pos];
                    continue;
                }
            }
            lastValueIsPlus = !lastValueIsPlus;
            list.add(v);
            v = array[pos];
        }
        list.add(v);
        // 如果得出数组首尾符号相同,则合并首尾

        if ((list.getFirst() > 0 && list.getLast() > 0) || list.getFirst() < 0 && list.getLast() < 0)
        {
            list.addFirst(list.removeFirst() + list.removeLast());
        }
        return list;
    }

    /**
     * 合并两个正数之间的负数小于这两个正数的和两个负数间的正数小于这两个负数
     */
    private void nearMerge(List<Integer> list)
    {
        for (int i = 1; i < list.size() - 1 && list.size() >= 3; i++)
        {
            Integer middle = list.get(i);
            // 正数

            if (middle > 0)
            {
                if (middle < -list.get(i - 1) && middle < -list.get(i + 1))
                {
                    merge3num(list, i);
                    i--;
                }
            }
            // 负数

            else
            {
                if (-middle < list.get(i - 1) && -middle < list.get(i + 1))
                {
                    merge3num(list, i);
                    i--;
                }
            }
        }
        /* 合并头尾 */
        // 合并头

        if (list.size() < 3)
            return;
        if (list.get(0) > 0)
        {
            if (list.get(0) <= -list.get(list.size() - 1) && list.get(0) <= -list.get(1))
            {
                int mergedValue = list.get(list.size() - 1) + list.get(0) + list.get(1);
                debug("merged pos: " + 0 + " value: " + list.get(list.size() - 1) + " " + list.get(0) + " "
                        + list.get(1) + " as " + mergedValue);
                list.remove(list.size() - 1);
                list.remove(1);
                list.remove(0);
                list.add(0, mergedValue);
                debug(list.toString());
            }
        }
        else
        {
            if (-list.get(0) <= list.get(list.size() - 1) && -list.get(0) <= list.get(1))
            {
                int mergedValue = list.get(list.size() - 1) + list.get(0) + list.get(1);
                debug("merged pos: " + 0 + " value: " + list.get(list.size() - 1) + " " + list.get(0) + " "
                        + list.get(1) + " as " + mergedValue);
                list.remove(list.size() - 1);
                list.remove(1);
                list.remove(0);
                list.add(0, mergedValue);
                debug(list.toString());
            }
        }
        // 合并尾

        if (list.size() < 3)
            return;
        if (list.get(list.size() - 1) > 0)
        {
            if (list.get(list.size() - 1) <= -list.get(list.size() - 2)
                    && list.get(list.size() - 1) <= -list.get(0))
            {
                int mergedValue = list.get(list.size() - 1) + list.get(0) + list.get(1);
                debug("merged pos: " + 0 + " value: " + list.get(list.size() - 2) + " "
                        + list.get(list.size() - 1) + " " + list.get(0) + " as " + mergedValue);
                list.remove(list.size() - 1);
                list.remove(list.size() - 1);
                list.remove(0);
                list.add(0, mergedValue);
                debug(list.toString());
            }
        }
        else
        {
            if (-list.get(list.size() - 1) <= list.get(list.size() - 2)
                    && -list.get(list.size() - 1) <= list.get(0))
            {
                int mergedValue = list.get(list.size() - 2) + list.get(0) + list.get(list.size() - 1);
                debug("merged pos: " + 0 + " value: " + list.get(list.size() - 2) + " "
                        + list.get(list.size() - 1) + " " + list.get(0) + " as " + mergedValue);
                list.remove(list.size() - 1);
                list.remove(list.size() - 1);
                list.remove(0);
                list.add(0, mergedValue);
                debug(list.toString());
            }
        }
    }

    /**
     * 把 List 中第 index 和它左右两个数相加后合并为一个数
     *
     * @param list
     * @param index
     */
    private void merge3num(List<Integer> list, int index)
    {
        int mergedValue = list.get(index - 1) + list.get(index) + list.get(index + 1);
        debug("merged pos: " + index + " value: " + list.get(index - 1) + " " + list.get(index) + " "
                + list.get(index + 1) + " as " + mergedValue);
        list.remove(index + 1);
        list.remove(index);
        list.remove(index - 1);
        list.add(index - 1, mergedValue);
        if (mergedValue > this.maxSum)
            this.maxSum = mergedValue;
        debug(list.toString());
    }

    private void setMax(List<Integer> list)
    {
        for (int i : list)
        {
            if (i > this.maxSum)
                this.maxSum = i;
        }
    }

    public static void main(String[] args)
    {
        Random random = new Random();
        int max = 10000;
        int[] is = new int[max];
        for (int i = 0; i < is.length; i++)
            is[i] = random.nextInt(max) - max / 2;
        Interview1 itv = new Interview1();
        itv.maxSubSequence(is);
        info("THE MAXSUM IS: " + itv.getMaxSum());
    }
}

分享到:
评论

相关推荐

    算法大全-面试题-数据结构.docx

    - **二级链表转一级链表**:遍历一级链表,对于每个节点,遍历其对应的二级链表,将二级链表的节点添加到一级链表的末尾。 - **交换链表中任意两个元素**:需要找到要交换的两个节点,以及它们的前一个节点,然后...

    JAVA经典算法面试39题及答案

    JAVA经典算法面试39题及答案 本资源总结了39道经典的 JAVA 算法面试题目,每个题目都附带答案,涵盖了常见的算法问题,旨在帮助读者更好地掌握 JAVA 编程语言和算法设计。 算法概述 算法是计算机科学中最重要的...

    面试高频算法题总结-剑指Offer题解

    面试高频算法题总结-剑指Offer题解,主要包含: 数据结构 数组 字符串 链表 栈和队列 二叉树 图 堆 线段树 字典树 单调栈 算法 二分查找 排序 递归 动态规划 分治 记忆化搜索 贪心 回溯 位运算 数学 设计 其他 共66...

    算法大全-面试题-链表-栈-二叉树-数据结构

    这通常通过两次遍历来完成:第一次遍历获取链表长度,第二次遍历至特定位置(长度减去3)。更高效的方法是使用双指针技术,其中一个指针先向前移动三步,然后两个指针同步移动,当先移动的指针到达链表尾部时,另一...

    算法大全-面试题-数据结构

    【算法大全-面试题-数据结构】主要涵盖了与单链表相关的多项操作,这些操作是数据结构和算法面试中常见的问题。以下是对每个知识点的详细解释: 1. **单链表反转**: - 算法1是迭代法,通过三个辅助变量curr, next...

    [最新答案V0.4版]微软等数据结构+算法面试100题[第41-60题答案]

    [第二部分]精选微软等公司结构+算法面试100题[前41-60题]: http://download.csdn.net/source/28117034 [第1题-60题汇总]微软等数据结构+算法面试100题 http://download.csdn.net/source/2826690答案系列: 5.[最新...

    Android面试算法题

    ### Android面试算法题知识点解析 #### 一、基础算法题:找出未放入数组中的两个数 **题目背景:** 在Android开发过程中,处理数组是非常常见的需求之一。此题旨在考察应聘者对基本数据结构(如数组)的理解以及...

    算法大全-面试题-数据结构1

    【算法大全-面试题-数据结构1】这篇文章主要探讨了单链表的相关操作,这些操作在面试中常常作为考察点,对于理解数据结构和算法至关重要。以下是对文章中提到的知识点的详细说明: 1. **单链表反转**:单链表反转是...

    算法大全-面试题-链表-栈-二叉树-数据结构.docx

    以上就是针对链表、栈、二叉树以及数据结构的一些常见面试题及其解题思路。这些知识点在实际的软件开发和算法设计中都有着广泛的应用。掌握这些基本操作和算法,对于提升编程能力和解决复杂问题的能力至关重要。

    算法面试经典 100题

    1. **双指针法**:使用两个指针,一个从第一个链表开始,另一个从第二个链表开始。 2. **同步移动**:当一个指针到达链表末尾时,将其移动到另一个链表的头部继续遍历。 **实现细节**: - 定义两个指针`p1`和`p2`,...

    华为od的面试算法真题

    ### 华为OD面试算法真题解析:抢7游戏 ...以上是对华为OD面试算法真题“抢7游戏”的详细解析及实现过程,通过此题不仅能够加深对应聘者对动态规划这一算法思想的理解,还能提高解决实际问题的能力。

    微软等公司数据结构+算法面试第1-100题汇总(21题-40题答案)

    ### 数据结构与算法面试知识点(21题-40题) #### 第21题:整数求和的所有可能组合 **题目描述**:输入两个整数`n`和`m`,从数列1,2,3,...,n中随意取几个数,使其和等于`m`,要求将其中所有的可能组合列出来。 ...

Global site tag (gtag.js) - Google Analytics