ตั้งทุกเซลล์ในเมทริกซ์เป็น 0 หากแถวหรือคอลัมน์นั้นมี 0


152

รับเมทริกซ์ NxN ด้วย 0s และ 1s ตั้งแถวที่มีทุก0ทุก0s และตั้งคอลัมน์ที่มีทุก0ทุก0วินาที

ตัวอย่างเช่น

1 0 1 1 0
0 1 1 1 0
1 1 1 1 1
1 0 1 1 1
1 1 1 1 1

ผลลัพธ์ใน

0 0 0 0 0
0 0 0 0 0
0 0 1 1 0
0 0 0 0 0
0 0 1 1 0

วิศวกรของ Microsoft บอกฉันว่ามีวิธีแก้ปัญหาที่ไม่มีหน่วยความจำเพิ่มเติมเพียงแค่ตัวแปรบูลีนสองตัวและหนึ่งรอบดังนั้นฉันจึงมองหาคำตอบนั้น

BTW ลองจินตนาการว่ามันเป็นเมทริกซ์บิตดังนั้นมีเพียง 1s และ 0s เท่านั้นที่อนุญาตให้อยู่ในเมทริกซ์


1
ฮะ? "เมื่อใดก็ตามที่คุณพบ" คืออะไร? คุณกำลังเผชิญกับองค์ประกอบอะไรบ้างในเมทริกซ์? และถ้าคุณพบบิตทั้งหมดคุณจะไม่ได้รับ 0 ทั้งหมดหรือไม่
ShreevatsaR

ลำดับที่คุณตัดสินใจที่จะเผชิญหน้ากับองค์ประกอบคือการตัดสินใจของคุณสิ่งนั้นคือคุณจะต้องตั้งค่าองค์ประกอบที่เหมาะสมเป็น 0 เท่านั้น หากคุณพบบิตทั้งหมดตั้งเป็น 0 ใช่เมทริกซ์จะยังคงเต็มไปด้วยศูนย์
jaircazarin- บัญชีเก่า

"องค์ประกอบที่เหมาะสม" คืออะไร คุณได้เมทริกซ์สองตัวหนึ่งเมทริกซ์ "ต้นทาง" และเมทริกซ์ "เป้าหมาย" หนึ่งรายการและคุณต้องตัดสินใจว่าจะ "พบ" องค์ประกอบใดเพื่อให้ได้เมทริกซ์ "เป้าหมาย"
ShreevatsaR

1
ฉันคิดว่าคุณคิดอะไรบางอย่างสำหรับ '1 รอบ' คิด มันสามารถทำได้เป็นเชิงเส้นใน 2 ผ่านแม้ว่าไม่มีหน่วยความจำพิเศษเพียง 2 booleans ;-) ดังนั้นฉันจึงคิดอย่างยิ่งว่ามันเป็นทางออกที่เขาหมายถึง (ดูด้านล่าง)
Piotr Lesnicki

1
คุณช่วยกรุณาตรวจสอบกับเพื่อนของคุณอีกครั้งหากคำอธิบายปัญหาถูกต้องจริงหรือไม่? ฉันคิดว่าฉันสามารถทำได้ด้วยรหัส Hamming หรือบิตพาริตี้ แต่จนถึงตอนนี้ฉันไม่ประสบความสำเร็จและปัญหายังคงตรึงอยู่ในหัวของฉัน :)
csl

คำตอบ:


96

ตกลงดังนั้นฉันเหนื่อยเพราะเป็นตี 3 ที่นี่ แต่ฉันได้ลองครั้งแรกด้วยการส่งผ่าน 2 ครั้งบนแต่ละหมายเลขในเมทริกซ์ดังนั้นใน O (NxN) และมันเป็นเส้นตรงในขนาดของเมทริกซ์

ฉันใช้คอลัมน์ 1 และแถวแรกเป็นเครื่องหมายเพื่อทราบว่าแถว / cols มีเพียง 1 ของ จากนั้นมีตัวแปร 2 ตัวคือ l และ c เพื่อให้จำได้ว่า 1rst แถว / คอลัมน์เป็น 1 ทั้งหมดเช่นกัน ดังนั้นรหัสผ่านแรกจะตั้งเครื่องหมายและรีเซ็ตส่วนที่เหลือเป็น 0

รอบที่สองกำหนด 1 ในสถานที่ที่แถวและ cols ที่ทำเครื่องหมายเป็น 1 และรีเซ็ตบรรทัดที่ 1 / คอลัมน์ขึ้นอยู่กับ l และ c

ฉันสงสัยอย่างมากว่าฉันสามารถทำได้ใน 1 รอบเป็นสี่เหลี่ยมในตอนเริ่มต้นขึ้นอยู่กับสี่เหลี่ยมในตอนท้าย บางทีบัตรที่สองของฉันอาจมีประสิทธิภาพมากกว่า ...

import pprint

m = [[1, 0, 1, 1, 0],
     [0, 1, 1, 1, 0],
     [1, 1, 1, 1, 1],
     [1, 0, 1, 1, 1],
     [1, 1, 1, 1, 1]]



N = len(m)

### pass 1

# 1 rst line/column
c = 1
for i in range(N):
    c &= m[i][0]

l = 1
for i in range(1,N):
    l &= m[0][i]


# other line/cols
# use line1, col1 to keep only those with 1
for i in range(1,N):
    for j in range(1,N):
        if m[i][j] == 0:
            m[0][j] = 0
            m[i][0] = 0
        else:
            m[i][j] = 0

### pass 2

# if line1 and col1 are ones: it is 1
for i in range(1,N):
    for j in range(1,N):
        if m[i][0] & m[0][j]:
            m[i][j] = 1

# 1rst row and col: reset if 0
if l == 0:
    for i in range(N):
        m [i][0] = 0

if c == 0:
    for j in range(1,N):
        m [0][j] = 0


pprint.pprint(m)

ปัญหาหนึ่งคือถ้า n> sizeof (c) มันจะพังลงมา หากต้องการขยายการทำงานในกรณีทั่วไปของ n คุณจะต้องปรับขนาดฟิลด์บิตของคุณแบบไดนามิกซึ่งฉันคิดว่าจะละเมิดข้อ จำกัด ที่เกิดจากปัญหา
อดัม

ไม่คไม่ใช่บิตฟิลด์มันเป็นเพียงเรื่องบูล & = ไม่ใช่ bitwise op (ก็คือ แต่สำหรับค่า 1 บิต) มีเพราะ c บอกคุณว่าคอลัมน์แรกคือทั้งหมด 1 (จริง) หรือมี 0 (false)
Steve Jessop

2
มันล้มเหลวถ้าแถวบนสุดคือ [0,1,1,1 ... ] การแก้ไขข้อผิดพลาดของฉันคือการเริ่มต้น l ถึง m [0] [0] มากกว่า 1
paperhorse

จริง l = 1 สำหรับฉันอยู่ในช่วง (1, N): l & = m [0] [i] ควรเป็น l = 1 สำหรับฉันอยู่ในช่วง (N): l & = m [0] [i]
Kristof Neirynck

1
BTW ฉันเชื่อว่าเงื่อนไขในรอบที่สองควรเป็นดังนี้: ถ้า m [i] [0] | m [0] [j]:
บัญชี jaircazarin เก่า

16

สิ่งนี้ไม่สามารถทำได้ในการส่งครั้งเดียวเนื่องจากบิตเดียวมีผลต่อบิตก่อนและหลังในการสั่งซื้อใด ๆ IOW ไม่ว่าคำสั่งใดที่คุณสำรวจอาร์เรย์คุณอาจเจอ 0 ซึ่งหมายความว่าคุณต้องย้อนกลับและเปลี่ยนค่า 1 ก่อนหน้าเป็น 0

ปรับปรุง

ผู้คนดูเหมือนจะคิดว่าการ จำกัด N ให้เป็นค่าคงที่ (พูด 8) คุณสามารถแก้ปัญหานี้ได้เพียงครั้งเดียว นั่นคือก) ขาดจุดและข) ไม่ใช่คำถามเดิม ฉันจะไม่โพสต์คำถามเกี่ยวกับการเรียงลำดับและคาดหวังคำตอบที่เริ่มต้น "สมมติว่าคุณต้องการเรียงลำดับ 8 สิ่ง ... "

ที่กล่าวมามันเป็นวิธีการที่สมเหตุสมผลถ้าคุณรู้ว่าจริง ๆ แล้ว N นั้นถูก จำกัด อยู่ที่ 8 คำตอบของฉันข้างต้นจะตอบคำถามเดิมซึ่งไม่มีข้อ จำกัด ดังกล่าว


ไม่สามารถทำได้ในครั้งเดียวโดยไม่มีหน่วยความจำเพิ่มเติม มันสามารถทำได้ในครั้งเดียวถ้ามีเมทริกซ์ NxN อีกอันที่จะเก็บผลไว้เช่นเดียวกันกับ twiddles เล็กน้อยและสองผ่านก็สามารถทำได้โดยไม่ต้องมีหน่วยความจำเพิ่มเติม
paxos1977

2
คุณยังไม่สามารถทำได้ในครั้งเดียวแม้ว่าคุณจะใช้เมทริกซ์ชั่วคราวหรืออย่างอื่นมีบางอย่างแปลก ๆ ที่ฉันไม่ได้รับที่นี่ คุณต้องผ่านหนึ่งครั้งเพื่ออนุมานข้อมูลแถว / คอลัมน์และอีกหนึ่งชุดเพื่อตั้งค่าทุกอย่าง
Lasse V. Karlsen

ฉันแก้ไขปัญหานี้ด้วยการตระหนักว่ามีค่าที่ไม่เป็นศูนย์เพียงค่าเดียวเท่านั้นที่เป็นไปได้ต่อแถวและเพิ่งกำหนดโดยอ้างอิง
Daniel Papasian

@ceretullis, lassevk: ฉันยังคิดว่ามันไม่สามารถทำได้ในรอบเดียว ส่งผ่านเมทริกซ์ที่สองนั้นจะต้องนับ - มิฉะนั้นคุณสามารถคัดลอกเมทริกซ์ในครั้งเดียวและทำงานกับสำเนาได้ตามที่คุณต้องการ @Daniel Papasian: โซลูชันของคุณไม่ได้ปรับขนาดที่ N> # บิตในแบบยาว / ยาว / อะไรก็ตาม
Draemon

Draemon เทคนิคการปรับขนาดนั้นเป็นเพียงคณิตศาสตร์ - คุณสามารถสร้างฮาร์ดแวร์ที่ทำหรือคุณสามารถใช้เทคนิคซอฟต์แวร์เพื่อจัดการตัวเลขที่มีขนาดใหญ่กว่าขนาดคำศัพท์ของคุณ ไม่ละเมิดข้อ จำกัด ของปัญหา IMHO
Daniel Papasian

10

ดังนั้นความคิดของฉันคือใช้ค่าในแถว / คอลัมน์สุดท้ายเป็นแฟล็กเพื่อระบุว่าค่าทั้งหมดในคอลัมน์ / แถวที่เกี่ยวข้องเป็น 1s หรือไม่

การใช้Zig Zag สแกนผ่านทั้งเมทริกซ์ยกเว้นแถว / คอลัมน์สุดท้าย ในแต่ละองค์ประกอบคุณตั้งค่าในแถว / คอลัมน์สุดท้ายตามลอจิคัล AND ของตัวเองพร้อมกับค่าในองค์ประกอบปัจจุบัน กล่าวอีกนัยหนึ่งถ้าคุณกด 0 แถว / คอลัมน์สุดท้ายจะถูกตั้งค่าเป็น 0 หากคุณเป็น 1 ค่าในแถว / คอลัมน์สุดท้ายจะเป็น 1 เท่านั้นหากเป็น 1 แล้ว ไม่ว่ากรณีใดก็ตามให้ตั้งค่าองค์ประกอบปัจจุบันเป็น 0

เมื่อคุณทำเสร็จแล้วแถว / คอลัมน์สุดท้ายของคุณควรมี 1s iff คอลัมน์ / แถวที่เกี่ยวข้องนั้นเต็มไปด้วย 1s

ทำการสแกนเชิงเส้นผ่านแถวและคอลัมน์สุดท้ายแล้วมองหา 1 วินาที ตั้งค่า 1s ในองค์ประกอบที่สอดคล้องกันในเนื้อความของเมทริกซ์โดยที่ทั้งแถวและคอลัมน์สุดท้ายเป็นทั้ง 1s

การเขียนโค้ดจะเป็นการยากที่จะหลีกเลี่ยงข้อผิดพลาดแบบออฟไลน์และอื่น ๆ แต่ควรทำงานในการส่งครั้งเดียว


ดีมาก ... ฉันกำลังคิดในบรรทัดเดียวกัน แต่พลาดการใช้แถว / คอลัมน์สุดท้ายเพื่อเก็บข้อมูลนั้นดังนั้นฉันจึงติดอยู่กับหน่วยความจำพิเศษสำหรับอาร์เรย์ Nx1 หนึ่งคู่
Dave Sherohman

1
ที่ดูเหมือนว่าสองผ่านให้ฉัน - หนึ่งผ่านคือสแกนซิกแซกที่สองคือ "การตั้งค่า 1s ในองค์ประกอบที่สอดคล้องกันในร่างกายของเมทริกซ์ที่แถวสุดท้ายและคอลัมน์ทั้งสองเป็น 1s"
Adam Rosenfield

การสแกนซิกแซก (ซึ่งบางคนชี้ให้ฉันเห็นว่าไม่จำเป็นอย่างยิ่ง) ข้ามผ่าน แต่แถว / คอลัมน์สุดท้าย ดังนั้นการสแกนคอลัมน์ / แถวสุดท้ายจึงไม่ได้ทำการสแกนองค์ประกอบที่ซ้ำกันก่อนหน้านี้ ดังนั้นหนึ่งผ่าน อีกนัยหนึ่งก็คือ O (N ^ 2) สำหรับเมทริกซ์ N * N
Alastair

6

ฉันมีวิธีแก้ปัญหาที่นี่มันทำงานในรอบเดียวและทำการประมวลผลทั้งหมด "ในสถานที่" โดยไม่ต้องมีหน่วยความจำเพิ่มเติม

ใช้การเรียกซ้ำเพื่อชะลอการเขียนค่าศูนย์ซึ่งแน่นอนว่าจะทำลายเมทริกซ์สำหรับแถวและคอลัมน์อื่น ๆ :

#include <iostream>

/**
* The idea with my algorithm is to delay the writing of zeros
* till all rows and cols can be processed. I do this using
* recursion:
* 1) Enter Recursive Function:
* 2) Check the row and col of this "corner" for zeros and store the results in bools
* 3) Send recursive function to the next corner
* 4) When the recursive function returns, use the data we stored in step 2
*       to zero the the row and col conditionally
*
* The corners I talk about are just how I ensure I hit all the row's a cols,
* I progress through the matrix from (0,0) to (1,1) to (2,2) and on to (n,n).
*
* For simplicities sake, I use ints instead of individual bits. But I never store
* anything but 0 or 1 so it's still fair ;)
*/

// ================================
// Using globals just to keep function
// call syntax as straight forward as possible
int n = 5;
int m[5][5] = {
                { 1, 0, 1, 1, 0 },
                { 0, 1, 1, 1, 0 },
                { 1, 1, 1, 1, 1 },
                { 1, 0, 1, 1, 1 },
                { 1, 1, 1, 1, 1 }
            };
// ================================

// Just declaring the function prototypes
void processMatrix();
void processCorner( int cornerIndex );
bool checkRow( int rowIndex );
bool checkCol( int colIndex );
void zeroRow( int rowIndex );
void zeroCol( int colIndex );
void printMatrix();

// This function primes the pump
void processMatrix() {
    processCorner( 0 );
}

// Step 1) This is the heart of my recursive algorithm
void processCorner( int cornerIndex ) {
    // Step 2) Do the logic processing here and store the results
    bool rowZero = checkRow( cornerIndex );
    bool colZero = checkCol( cornerIndex );

    // Step 3) Now progress through the matrix
    int nextCorner = cornerIndex + 1;
    if( nextCorner < n )
        processCorner( nextCorner );

    // Step 4) Finially apply the changes determined earlier
    if( colZero )
        zeroCol( cornerIndex );
    if( rowZero )
        zeroRow( cornerIndex );
}

// This function returns whether or not the row contains a zero
bool checkRow( int rowIndex ) {
    bool zero = false;
    for( int i=0; i<n && !zero; ++i ) {
        if( m[ rowIndex ][ i ] == 0 )
            zero = true;
    }
    return zero;
}

// This is just a helper function for zeroing a row
void zeroRow( int rowIndex ) {
    for( int i=0; i<n; ++i ) {
        m[ rowIndex ][ i ] = 0;
    }
}

// This function returns whether or not the col contains a zero
bool checkCol( int colIndex ) {
    bool zero = false;
    for( int i=0; i<n && !zero; ++i ) {
        if( m[ i ][ colIndex ] == 0 )
            zero = true;
    }

    return zero;
}

// This is just a helper function for zeroing a col
void zeroCol( int colIndex ) {
    for( int i=0; i<n; ++i ) {
        m[ i ][ colIndex ] = 0;
    }
}

// Just a helper function for printing our matrix to std::out
void printMatrix() {
    std::cout << std::endl;
    for( int y=0; y<n; ++y ) {
        for( int x=0; x<n; ++x ) {
            std::cout << m[y][x] << " ";
        }
        std::cout << std::endl;
    }
    std::cout << std::endl;
}

// Execute!
int main() {
    printMatrix();
    processMatrix();
    printMatrix();
}

2
วิธีแก้ปัญหาที่ดี แต่คุณใช้เทคนิคในการใช้หน่วยความจำมากกว่า booleans ที่อนุญาตสองอัน
csl

1
นี่คือ> 1 รอบ หากคุณพิมพ์ (rowIndex, i) และ (i, colIndex) เนื่องจากมีการเข้าถึงใน checkRow และ checkCol คุณจะเห็นว่าแต่ละองค์ประกอบมีการเข้าถึงหลายครั้ง
Draemon

Draemon: ถูกต้องฉันคิดว่าเราต้องการคำจำกัดความที่ชัดเจนของ "single pass" จากผู้ผลิตปริศนา หากเขาหมายถึงว่าแต่ละองค์ประกอบสามารถเข้าถึงได้เพียงครั้งเดียวเท่านั้นเราจำเป็นต้องมีวิธีแก้ไขปัญหาที่แตกต่างกัน
อดัม

ฉันจินตนาการถึงปัญหาดั้งเดิม (ซึ่งมาหาเราผ่านเกมโทรศัพท์) หมายความว่าปัญหาควรได้รับการแก้ไข "แทนที่" ซึ่งหมายความว่าคุณไม่มีสำเนาของเมทริกซ์อีก และโซลูชันที่เหมาะสมที่สุดไม่จำเป็นต้องมีการสลับชั่วคราว () เช่นการจัดเก็บข้อมูลสำหรับการประมวลผล
อดัม

นอกจากนี้ฉันสงสัยว่าข้อ จำกัด หมายถึงรหัสเครื่องที่เกิดขึ้น ความหมาย "รหัส" ที่ฉันให้ไว้ใช้เพียง 2 ตัว ขึ้นอยู่กับการเพิ่มประสิทธิภาพของคอมไพเลอร์ของฉันสิ่งที่ยี้ทั้งหมดอาจ inline หรือผู้รู้อะไร ฉันคิดว่าวิธีแก้ปัญหาของฉันนั้นถูกต้อง;)
Adam

4

ฉันไม่คิดว่ามันจะเป็นไปได้ เมื่อคุณอยู่ในจตุรัสแรกและค่าของมันคือ 1 คุณจะไม่มีทางรู้เลยว่าค่าของช่องสี่เหลี่ยมอื่น ๆ ในแถวและคอลัมน์เดียวกันคืออะไร ดังนั้นคุณต้องตรวจสอบสิ่งเหล่านั้นและถ้ามีศูนย์ให้กลับไปที่จตุรัสแรกและเปลี่ยนค่าเป็นศูนย์ ฉันจะแนะนำให้ทำในสองรอบ - ผ่านแรกรวบรวมข้อมูลเกี่ยวกับแถวและคอลัมน์ที่จะต้องเป็นศูนย์ออก (ข้อมูลจะถูกเก็บไว้ในอาร์เรย์ดังนั้นเราจึงใช้หน่วยความจำเพิ่มเติมบางอย่าง) รอบที่สองเปลี่ยนค่า ฉันรู้ว่านั่นไม่ใช่วิธีการแก้ปัญหาที่คุณกำลังมองหา แต่ฉันคิดว่ามันเป็นวิธีที่ใช้ได้จริง ข้อ จำกัด ที่คุณให้ไว้ไม่สามารถแก้ไขปัญหาได้


ฉันมีวิธีแก้ปัญหาเดียวกันเกือบทั้งหมด (ดูด้านล่าง) โดยไม่มีอาร์เรย์เพิ่มเติม และเป็นเวลาเชิงเส้น (แต่ผ่านไป 2 ครั้ง)
Piotr Lesnicki

@Piotr: ใช่ผ่านที่สองดูเหมือนจะหลีกเลี่ยงไม่ได้ การแนะนำอาร์เรย์เพื่อจัดเก็บข้อมูลแถวและคอลัมน์ที่ฉันเสนอทำให้อัลกอริทึมตรงไปข้างหน้ามากขึ้นและเร็วขึ้นเล็กน้อยเนื่องจากมีการตรวจสอบและการเปลี่ยนแปลงค่าน้อยลง เป็นการแลกเปลี่ยนระหว่างการจัดเก็บและประสิทธิภาพ
Boyan

3

ฉันสามารถทำได้ด้วยตัวแปรจำนวนเต็มสองตัวและการส่งผ่านสองครั้ง (มากถึง 32 แถวและคอลัมน์ ... )

bool matrix[5][5] = 
{ 
    {1, 0, 1, 1, 0},
    {0, 1, 1, 1, 0},
    {1, 1, 1, 1, 1},
    {1, 0, 1, 1, 1},
    {1, 1, 1, 1, 1}
};

int CompleteRows = ~0;
int CompleteCols = ~0;

// Find the first 0
for (int row = 0; row < 5; ++row)
{
    for (int col = 0; col < 5; ++col)
    {
        CompleteRows &= ~(!matrix[row][col] << row);
        CompleteCols &= ~(!matrix[row][col] << col);
    }
}

for (int row = 0; row < 5; ++row)
    for (int col = 0; col < 5; ++col)
        matrix[row][col] = (CompleteRows & (1 << row)) && (CompleteCols & (1 << col));

นี่คือ C # หรือไม่ ~ หมายถึงอะไร
sker

มันคือ C ++ ~กลับค่าบิตทั้งหมดในตัวแปร 0x00000000 กลายเป็น 0x00000000 ฉันเริ่มต้นด้วยทุกสิ่งและลบบิตสำหรับแถว / คอลัมน์เมื่อฉันพบ 0 CompleteCols มีบิต 2 และ 3 ชุดและ CompleteRows มีบิต 2 และ 4 ชุด (ตาม 0)
Eclipse

จากนั้นคุณเพียงตั้งค่าบิตในเมทริกซ์ที่สอดคล้องกับหนึ่งในทั้ง CompleteCols และ CompleteRows
Eclipse

3

ปัญหาสามารถแก้ไขได้ในครั้งเดียว

บันทึกเมทริกซ์ในอาร์เรย์ i X j

1 0 1 1 0
0 1 1 1 0
1 1 1 1 1
1 0 1 1 1 
1 1 1 1 1

one each pass save the values of i and j for an element which is 0 in arrays a and b
when first row is scanned a= 1 b = 2,5
when second row is scanned a=1,2 b= 1,2,5
when third row is scanned no change
when fourth row is scanned a= 1,2,4 and b= 1,2,5
when fifth row is scanned no change .

ตอนนี้พิมพ์ค่าทั้งหมดเป็น 0 สำหรับค่าของ i และ j ที่บันทึกใน a และ b ส่วนที่เหลือของค่าคือ 1 คือ (3,3) (3,4) (5,3) และ (5,4)


1

อีกวิธีหนึ่งที่ใช้เวลาสองรอบคือการสะสม ANDs ในแนวนอนและแนวตั้ง:

1 0 1 1 0 | 0
0 1 1 1 0 | 0
1 1 1 1 1 | 1
1 0 1 1 1 | 0
1 1 1 1 1 | 1
----------+
0 0 1 1 0    

ฉันคิดว่าฉันสามารถออกแบบขั้นตอนวิธีการดังกล่าวโดยใช้บิตเท่าเทียมกัน , รหัส Hammingหรือเขียนโปรแกรมแบบไดนามิกอาจจะใช้ทั้งสอง booleans เป็นจำนวน 2 บิต แต่ฉันไม่ประสบความสำเร็จเลย

คุณช่วยตรวจสอบคำแถลงปัญหากับวิศวกรของคุณอีกครั้งและแจ้งให้เราทราบได้ไหม หากมีเป็นจริงการแก้ปัญหาผมต้องการที่จะให้แกะออกไปที่ปัญหาที่เกิดขึ้น


1

เก็บตัวแปรตัวเดียวเพื่อติดตามว่าแถวทั้งหมดเป็นอย่างไร

หากแถวคือ -1 (all 1s) ให้ทำการอ้างอิงแถวถัดไปกับตัวแปรนั้น

ถ้าแถวเป็นอะไร แต่มันคือ 0 คุณสามารถทำทุกอย่างได้ในครั้งเดียว หลอกรหัส:

foreach (my $row) rows {
     $andproduct = $andproduct & $row;
     if($row != -1) {
        zero out the row
     }  else {
        replace row with a reference to andproduct
     }
}

สิ่งนี้ควรทำในการส่งครั้งเดียว - แต่มีข้อสันนิษฐานที่นี่ว่า N มีขนาดเล็กพอสำหรับให้ CPU ทำเลขคณิตในแถวเดียวมิฉะนั้นคุณจะต้องวนรอบแต่ละแถวเพื่อตรวจสอบว่าเป็นไปได้หรือไม่ 1s หรือไม่ฉันเชื่อว่า แต่เมื่อคุณถามเกี่ยวกับ algos และไม่ จำกัด ฮาร์ดแวร์ของฉันฉันจะเริ่มตอบด้วย "สร้าง CPU ที่รองรับ N-bit arithmetic ... "

นี่คือตัวอย่างหนึ่งที่สามารถทำได้ใน C. หมายเหตุฉันยืนยันว่าค่าและ arr ที่รวมเข้าด้วยกันเป็นตัวแทนของอาร์เรย์และ p และ numproduct คือตัววนซ้ำของฉันและตัวแปรผลิตภัณฑ์ AND ใช้เพื่อทำให้เกิดปัญหา (ฉันสามารถวนรอบ arr กับเลขคณิตตัวชี้เพื่อตรวจสอบงานของฉัน แต่ครั้งหนึ่งก็เพียงพอแล้ว!)

int main() {
    int values[] = { -10, 14, -1, -9, -1 }; /* From the problem spec, converted to decimal for my sanity */
    int *arr[5] = { values, values+1, values+2, values+3, values+4 };
    int **p;
    int numproduct = 127;

    for(p = arr; p < arr+5; ++p) {
        numproduct = numproduct & **p;
        if(**p != -1) {
            **p = 0;
        } else {
            *p = &numproduct;
        }
    }

    /* Print our array, this loop is just for show */
    int i;
    for(i = 0; i < 5; ++i) {
        printf("%x\n",*arr[i]);
    }
    return 0;
}

สิ่งนี้จะสร้าง 0, 0, 6, 0, 6 ซึ่งเป็นผลลัพธ์สำหรับอินพุตที่กำหนด

หรือใน PHP ถ้าคนคิดว่าเกมสแต็คของฉันใน C กำลังโกง (ฉันแนะนำให้คุณรู้ว่ามันไม่ใช่เพราะฉันควรจะสามารถเก็บเมทริกซ์ได้ตามที่ฉันต้องการ):

<?php

$values = array(-10, 14, -1, -9, -1);
$numproduct = 127;

for($i = 0; $i < 5; ++$i) {
    $numproduct = $numproduct & $values[$i];
    if($values[$i] != -1) {
        $values[$i] = 0;
    } else {
        $values[$i] = &$numproduct;
    }
}

print_r($values);

ฉันพลาดอะไรไปรึเปล่า?


วิธีนี้ใช้ไม่ได้ถ้า N ใหญ่กว่าจำนวนบิตใน int / long / อะไรก็ตามฉันไม่คิดว่ามันจะนับ
Draemon

มันจะไม่จับสิ่งต่าง ๆ ถ้า 0 อยู่ด้านล่างของอาร์เรย์ (ลองด้วยค่า [] = {-1, -9, -1, 14, -10})
Eclipse

Draemon ฉันระบุในคำตอบว่าไม่มีข้อ จำกัด ด้านฮาร์ดแวร์เป็นส่วนหนึ่งของคำถามคุณเริ่มต้นด้วย "Build a CPU ที่รองรับ N-bit arithmetic"
Daniel Papasian

จอชฉันไม่ทำตาม ด้วยโซลูชัน C หรือ PHP และอาร์เรย์ที่คุณแนะนำฉันได้รับ 6 0 6 0 0 ซึ่งฉันเชื่อว่าเป็นคำตอบที่ถูกต้อง
Daniel Papasian

@Daniel - คุณทำไม่ได้เพราะ N ไม่ใช่ค่าคงที่ นอกจากนี้ "การสร้างคอมพิวเตอร์เครื่องใหม่ด้วยคำ 1Mbit นั้นไม่ค่อยเป็นขั้นตอนวิธีที่สมเหตุสมผล
Draemon

1

Nice challange วิธีการแก้ปัญหาประเภทนี้ใช้เพียงสอง booleans ที่สร้างขึ้นบนสแต็ก แต่ booleans ถูกสร้างขึ้นหลายครั้งบนสแต็กเนื่องจากฟังก์ชันนี้เรียกซ้ำ

typedef unsigned short     WORD;
typedef unsigned char      BOOL;
#define true  1
#define false 0
BYTE buffer[5][5] = {
1, 0, 1, 1, 0,
0, 1, 1, 1, 0,
1, 1, 1, 1, 1,
1, 0, 1, 1, 1,
1, 1, 1, 1, 1
};
int scan_to_end(BOOL *h,BOOL *w,WORD N,WORD pos_N)
{
    WORD i;
    for(i=0;i<N;i++)
    {
        if(!buffer[i][pos_N])
            *h=false;
        if(!buffer[pos_N][i])
            *w=false;
    }
    return 0;
}
int set_line(BOOL h,BOOL w,WORD N,WORD pos_N)
{
    WORD i;
    if(!h)
        for(i=0;i<N;i++)
            buffer[i][pos_N] = false;
    if(!w)
        for(i=0;i<N;i++)
            buffer[pos_N][i] = false;
    return 0;
}
int scan(int N,int pos_N)
{
    BOOL h = true;
    BOOL w = true;
    if(pos_N == N)
        return 0;
    // Do single scan
    scan_to_end(&h,&w,N,pos_N);
    // Scan all recursive before changeing data
    scan(N,pos_N+1);
    // Set the result of the scan
    set_line(h,w,N,pos_N);
    return 0;
}
int main(void)
{
    printf("Old matrix\n");
    printf( "%d,%d,%d,%d,%d \n", (WORD)buffer[0][0],(WORD)buffer[0][1],(WORD)buffer[0][2],(WORD)buffer[0][3],(WORD)buffer[0][4]);
    printf( "%d,%d,%d,%d,%d \n", (WORD)buffer[1][0],(WORD)buffer[1][1],(WORD)buffer[1][2],(WORD)buffer[1][3],(WORD)buffer[1][4]);
    printf( "%d,%d,%d,%d,%d \n", (WORD)buffer[2][0],(WORD)buffer[2][1],(WORD)buffer[2][2],(WORD)buffer[2][3],(WORD)buffer[2][4]);
    printf( "%d,%d,%d,%d,%d \n", (WORD)buffer[3][0],(WORD)buffer[3][1],(WORD)buffer[3][2],(WORD)buffer[3][3],(WORD)buffer[3][4]);
    printf( "%d,%d,%d,%d,%d \n", (WORD)buffer[4][0],(WORD)buffer[4][1],(WORD)buffer[4][2],(WORD)buffer[4][3],(WORD)buffer[4][4]);
    scan(5,0);
    printf("New matrix\n");
    printf( "%d,%d,%d,%d,%d \n", (WORD)buffer[0][0],(WORD)buffer[0][1],(WORD)buffer[0][2],(WORD)buffer[0][3],(WORD)buffer[0][4]);
    printf( "%d,%d,%d,%d,%d \n", (WORD)buffer[1][0],(WORD)buffer[1][1],(WORD)buffer[1][2],(WORD)buffer[1][3],(WORD)buffer[1][4]);
    printf( "%d,%d,%d,%d,%d \n", (WORD)buffer[2][0],(WORD)buffer[2][1],(WORD)buffer[2][2],(WORD)buffer[2][3],(WORD)buffer[2][4]);
    printf( "%d,%d,%d,%d,%d \n", (WORD)buffer[3][0],(WORD)buffer[3][1],(WORD)buffer[3][2],(WORD)buffer[3][3],(WORD)buffer[3][4]);
    printf( "%d,%d,%d,%d,%d \n", (WORD)buffer[4][0],(WORD)buffer[4][1],(WORD)buffer[4][2],(WORD)buffer[4][3],(WORD)buffer[4][4]);
    system( "pause" );
    return 0;
}

สแกนในรูปแบบที่ชอบ:

s,s,s,s,s
s,0,0,0,0
s,0,0,0,0
s,0,0,0,0
s,0,0,0,0


0,s,0,0,0
s,s,s,s,s
0,s,0,0,0
0,s,0,0,0
0,s,0,0,0

และอื่น ๆ

จากนั้นเปลี่ยนค่าในรูปแบบนี้เมื่อกลับมาที่แต่ละฟังก์ชั่นการสแกน (ล่างขึ้นบน):

0,0,0,0,c
0,0,0,0,c
0,0,0,0,c
0,0,0,0,c
c,c,c,c,c


0,0,0,c,0
0,0,0,c,0
0,0,0,c,0
c,c,c,c,c
0,0,0,c,0

และอื่น ๆ


ฉันเดาว่านี่ไม่ถูกต้องเนื่องจากคุณยังคงใช้บูลีนมากกว่าสองในกองซ้อนของคุณ
csl

ในขณะที่ฉันเศร้าคู่หูสองคน นี่คือสิ่งที่ใกล้เคียงที่สุดที่ฉันสามารถนึกถึงสเป็คที่เขาจัดหาให้ได้ ฉันชอบที่จะเห็นทางออกที่แท้จริงที่นี่ ถ้ามันเป็น fesable
eaanon01

ฉันไม่คิดว่าข้อกำหนดนั้นหมายถึงการเติบโตของกองซ้อน ฉันคิดว่านี่เป็นทางออกที่ถูกต้องอย่างสมบูรณ์
อดัม

นั่นคือเจ้าของฉันเช่นกัน แต่ฉันไม่แน่ใจจนกว่าจะมีคนอื่นโพสต์เป็นทางออกที่ดีกว่า อย่างน้อยโซลูชันของฉันสามารถคอมไพล์ได้และสามารถตรวจสอบได้โดยทุกคน :) ... ฉันไม่พบรหัส psudo สำหรับปัญหาในทางปฏิบัติ ขอบคุณ
eaanon01

1

โอเคนี่เป็นทางออกที่

  • ใช้ค่ายาวพิเศษเพียงหนึ่งสำหรับการจัดเก็บข้อมูลที่ใช้งานได้
  • ไม่มีการเรียกซ้ำ
  • หนึ่งผ่านของ N เท่านั้นไม่ใช่แม้แต่ N * N
  • จะทำงานกับค่าอื่น ๆ ของ N แต่จะต้อง #defines ใหม่
#include <stdio.h>
#define BIT30 (1<<24)
#define COLMASK 0x108421L
#define ROWMASK 0x1fL
unsigned long long STARTGRID = 
((0x10 | 0x0 | 0x4 | 0x2 | 0x0) << 20) |
((0x00 | 0x8 | 0x4 | 0x2 | 0x0) << 15) |
((0x10 | 0x8 | 0x4 | 0x2 | 0x1) << 10) |
((0x10 | 0x0 | 0x4 | 0x2 | 0x1) << 5) |
((0x10 | 0x8 | 0x4 | 0x2 | 0x1) << 0);


void dumpGrid (char* comment, unsigned long long theGrid) {
    char buffer[1000];
    buffer[0]='\0';
    printf ("\n\n%s\n",comment);
    for (int j=1;j<31; j++) {
        if (j%5!=1)
            printf( "%s%s", ((theGrid & BIT30)==BIT30)? "1" : "0",(((j%5)==0)?"\n" : ",") );    
        theGrid = theGrid << 1;
    }
}

int main (int argc, const char * argv[]) {
    unsigned long long rowgrid = STARTGRID;
    unsigned long long colGrid = rowgrid;

    unsigned long long rowmask = ROWMASK;
    unsigned long long colmask = COLMASK;

    dumpGrid("Initial Grid", rowgrid);
    for (int i=0; i<5; i++) {
        if ((rowgrid & rowmask)== rowmask) rowgrid |= rowmask;
        else rowgrid &= ~rowmask;
        if ((colGrid & colmask) == colmask) colmask |= colmask;
        else colGrid &=  ~colmask;
        rowmask <<= 5;
        colmask <<= 1;
    }
    colGrid &= rowgrid;
    dumpGrid("RESULT Grid", colGrid);
    return 0;
    }

มันเป็นทางออกที่ดีที่จะแน่ใจ และฉันคิดว่าวิธีแก้ปัญหาทุกคนที่นี่ละเลยข้อกำหนดอย่างน้อยหนึ่งข้อ ดังนั้นการแก้ปัญหาด้วยค่าสูงสุดที่อนุญาตสำหรับ N จึงไม่ใช่สิ่งที่เลวร้ายที่สุดในโลกงานที่ดีมากสำหรับงานนี้ :)
Adam

การ จำกัด N ถึง 8 และอ้างว่าสิ่งนี้ตรงตามข้อกำหนดของบัตรผ่านเดียวเป็นเพียงใบสมัครเล่นที่เรียบง่าย นี่ไม่ใช่วิธีแก้ไขปัญหาทั่วไป ไม่มีการ จำกัด ขนาดของ N ที่ระบุไว้ในคำถามดังนั้นคุณจึงแก้ปัญหาย่อยได้เท่านั้น
Draemon

แต่โซลูชันเหล่านี้ทั้งหมดมีข้อ จำกัด ใน N ในทางเดียวหรืออื่น
AnthonyLambert

การบอกว่ามันเป็นหนึ่งผ่านของ N เห็นได้ชัดว่าผิดทั้งหมด แม้แต่การอ่านค่าของแต่ละตำแหน่งในเมทริกซ์ดั้งเดิมก็คือ O (N ^ 2) และจำเป็นอย่างยิ่งที่จะต้องอ่านค่าของแต่ละตำแหน่งอย่างน้อยหนึ่งครั้งเพื่อให้สามารถคำนวณวิธีแก้ปัญหาได้ แม้ว่าคุณเก็บค่าเป็นบิตเดียวภายในระยะเวลานานการเข้าถึงแต่ละบิตจะเป็น O (N ^ 2) เพราะมีบิต O (N ^ 2)
Alderath

เป็นที่ชัดเจนว่าการส่งผ่านค่า RowGrid จะเก็บกริดทั้งหมดและหลังจากการอ่านครั้งแรกจะเป็นหนึ่งในตัวประมวลผลที่ลงทะเบียนสำหรับอัลกอริทึมทั้งหมดหากเครื่องมือเพิ่มประสิทธิภาพใด ๆ ที่ดี
AnthonyLambert

1

แท้จริง หากคุณต้องการเรียกใช้อัลกอริทึมและพิมพ์ผลลัพธ์ (เช่นไม่คืนค่าพวกเขาสิ่งนี้สามารถทำได้อย่างง่ายดายในหนึ่งรอบปัญหามาเมื่อคุณพยายามที่จะปรับเปลี่ยนอาร์เรย์ในขณะที่คุณกำลังเรียกใช้อัลกอริทึม

นี่คือโซลูชันของฉันมันเกี่ยวข้องกับการบวกค่าแถว / คอลัมน์สำหรับองค์ประกอบของ givein (i, j) และพิมพ์ออกมา

#include <iostream>
#include "stdlib.h"

void process();

int dim = 5;
bool m[5][5]{{1,0,1,1,1},{0,1,1,0,1},{1,1,1,1,1},{1,1,1,1,1},{0,0,1,1,1}};


int main() {
    process();
    return 0;
}

void process() {
    for(int j = 0; j < dim; j++) {
        for(int i = 0; i < dim; i++) {
            std::cout << (
                          (m[0][j] & m[1][j] & m[2][j] & m[3][j] & m[4][j]) &
                          (m[i][0] & m[i][1] & m[i][2] & m[i][3] & m[i][4])
                          );
        }
        std::cout << std::endl;
    }
}

1

ฉันพยายามที่จะแก้ปัญหานี้ใน C #

ฉันใช้ตัวแปรลูปสองตัว (i และ j) นอกเหนือจากเมทริกซ์จริงและ n แทนมิติ

ตรรกะที่ฉันพยายามคือ:

  1. คำนวณและสำหรับแถวและคอลัมน์ที่เกี่ยวข้องในตารางศูนย์กลางของเมทริกซ์
  2. เก็บไว้ในเซลล์มุมของมัน (ฉันเก็บไว้ในลำดับทวนเข็มนาฬิกา)
  3. ตัวแปรบูลสองตัวถูกใช้เพื่อรักษาค่าของสองมุมเมื่อประเมินสแควร์เฉพาะ
  4. กระบวนการนี้จะสิ้นสุดเมื่อวงรอบนอก (i) อยู่กึ่งกลาง
  5. ประเมินผลลัพธ์ของเซลล์อื่น ๆ ตามเซลล์มุม (สำหรับส่วนที่เหลือของฉัน) ข้ามเซลล์มุมระหว่างกระบวนการนี้
  6. เมื่อฉันไปถึง n เซลล์ทั้งหมดจะมีผลลัพธ์ยกเว้นเซลล์มุม
  7. อัพเดตเซลล์มุม นี่คือการทำซ้ำพิเศษต่อความยาวของ n / 2 นอกเหนือจากข้อ จำกัด การส่งผ่านเดี่ยวที่กล่าวถึงในปัญหา

รหัส:

void Evaluate(bool [,] matrix, int n)
{
    bool tempvar1, tempvar2;

    for (var i = 0; i < n; i++)
    {
        tempvar1 = matrix[i, i];
        tempvar2 = matrix[n - i - 1, n - i - 1];

        var j = 0;

        for (j = 0; j < n; j++)
        {
            if ((i < n/2) || (((n % 2) == 1) && (i == n/2) && (j <= i)))
            {
                // store the row and col & results in corner cells of concentric squares
                tempvar1 &= matrix[j, i];
                matrix[i, i] &= matrix[i, j];
                tempvar2 &= matrix[n - j - 1, n - i - 1];
                matrix[n - i - 1, n - i - 1] &= matrix[n - i - 1, n - j - 1];
            }
            else
            {
                // skip corner cells of concentric squares
                if ((j == i) || (j == n - i - 1)) continue;

                // calculate the & values for rest of them
                matrix[i, j] = matrix[i, i] & matrix[n - j - 1, j];
                matrix[n - i - 1, j] = matrix[n - i - 1, n - i - 1] & matrix[n - j - 1, j];

                if ((i == n/2) && ((n % 2) == 1))
                {
                    // if n is odd
                    matrix[i, n - j - 1] = matrix[i, i] & matrix[j, n - j - 1];
                }
            }
        }

        if ((i < n/2) || (((n % 2) == 1) && (i <= n/2)))
        {
            // transfer the values from temp variables to appropriate corner cells of its corresponding square
            matrix[n - i - 1, i] = tempvar1;
            matrix[i, n - i - 1] = tempvar2;
        }
        else if (i == n - 1)
        {
            // update the values of corner cells of each concentric square
            for (j = n/2; j < n; j++)
            {
                tempvar1 = matrix[j, j];
                tempvar2 = matrix[n - j - 1, n - j - 1];

                matrix[j, j] &= matrix[n - j - 1, j];
                matrix[n - j - 1, j] &= tempvar2;

                matrix[n - j - 1, n - j - 1] &= matrix[j, n - j - 1];
                matrix[j, n - j - 1] &= tempvar1;
            }
        }
    }
}

1

One Pass - ฉันเข้าไปสำรวจอินพุตเพียงครั้งเดียว แต่ใช้อาร์เรย์ใหม่และมีตัวแปรบูลีนพิเศษสองตัวเท่านั้น

public static void main(String[] args) {

        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        sc.nextLine();

        boolean rowDel = false, colDel = false;
        int arr[][] = new int[n][n];
        int res[][] = new int[n][n];
        int i, j;
        for (i = 0; i < n; i++) {

            for (j = 0; j < n; j++) {
                arr[i][j] = sc.nextInt();
                res[i][j] = arr[i][j];  
            }
        }

        for (i = 0; i < n; i++) {

            for (j = 0; j < n; j++) {
                if (arr[i][j] == 0)
                    colDel = rowDel = true; //See if we have to delete the
                                            //current row and column
                if (rowDel == true){
                    res[i] = new int[n];
                    rowDel = false;
                }
                if(colDel == true){
                    for (int k = 0; k < n; k++) {
                        res[k][j] = 0;
                    }
                    colDel = false;
                }

            }

        }

        for (i = 0; i < n; i++) {

            for (j = 0; j < n; j++) {
                System.out.print(res[i][j]);
            }
            System.out.println();
        }
        sc.close();

    }

0

ในขณะที่เป็นไปไม่ได้เนื่องจากข้อ จำกัด วิธีที่มีประสิทธิภาพในการใช้พื้นที่มากที่สุดคือการสำรวจเมทริกซ์ด้วยการสลับแถว / คอลัมน์สลับกันซึ่งจะทำให้รูปแบบคล้ายกับการวางอิฐในรูปแบบซิกแซก:

-----
|----
||---
|||--
||||-

เมื่อใช้สิ่งนี้คุณจะไปในแต่ละแถว / คอลัมน์ตามที่ระบุไว้และหากคุณพบ 0 ในเวลาใดก็ได้ให้ตั้งค่าตัวแปรบูลีนและเดินแถว / คอลัมน์นั้นซ้ำอีกครั้งตั้งค่ารายการเป็น 0 ตามที่คุณต้องการ

สิ่งนี้จะไม่ต้องการหน่วยความจำเพิ่มเติมและจะใช้ตัวแปรบูลีนเดียวเท่านั้น น่าเสียดายถ้าขอบ "ไกล" ถูกตั้งค่าเป็น 0 นั่นเป็นกรณีที่แย่ที่สุดและคุณเดินอาร์เรย์ทั้งหมดสองครั้ง


ฉันอาจจะผิด แต่คุณแน่ใจหรือว่าทำงานได้? เมื่อคุณทำคอลัมน์ที่ 3 คุณจะรู้ได้อย่างไรว่ามูลค่าที่ด้านบนสุดของแถวนั้นเป็น 1 หรือ 0 ก่อนที่คุณจะประมวลผลแถวแรก
Steve Jessop

คุณไม่รู้ แต่ก็ไม่จำเป็นด้วย ถ้าเป็น 0 ทั้งคอลัมน์จะต้องเป็น 0 หากค่าในแถวก่อนหน้าเป็น 1 คุณจะรู้ว่าแถวทั้งหมดข้างบนเป็น 1 (และเป็นไปได้เสมอ)
Dave Sherohman

0

สร้างเมทริกซ์ผลลัพธ์และตั้งค่าทั้งหมดเป็น 1 ผ่านเมทริกซ์ข้อมูลทันทีที่พบ 0 ให้ตั้งค่าคอลัมน์แถวเมทริกซ์ผลลัพธ์เป็น 0

เมื่อสิ้นสุดรอบแรกเมทริกซ์ผลลัพธ์จะมีคำตอบที่ถูกต้อง

ดูเรียบง่าย มีเคล็ดลับที่ฉันหายไปหรือไม่? คุณไม่ได้รับอนุญาตให้ใช้ชุดผลลัพธ์หรือไม่

แก้ไข:

ดูเหมือนว่าฟังก์ชั่น F # แต่นั่นเป็นการโกงนิดหน่อยตั้งแต่แม้ว่าคุณจะทำผ่านเดียวฟังก์ชั่นสามารถเรียกซ้ำ

ดูเหมือนว่าผู้สัมภาษณ์พยายามคิดออกหากคุณรู้ว่าการเขียนโปรแกรมใช้งานได้


1
การใช้ชุดผลลัพธ์จะเป็นการเพิ่มหน่วยความจำ
cdeszaq

ฟังก์ชั่นการเขียนโปรแกรมจะไม่แก้ไขอาเรย์ดั้งเดิมในสถานที่
Svante

0

ฉันมากับโซลูชัน pass เดียวในสถานที่ (ไม่ใช่แบบเรียกซ้ำ) โดยใช้ 4 bools และ 2 loop counters ฉันไม่ได้จัดการลดมันให้เหลือ 2 ตัวและ 2 ตัว แต่ฉันจะไม่แปลกใจถ้ามันเป็นไปได้ มันอ่านได้ประมาณ 3 ครั้งและ 3 เขียนของแต่ละเซลล์และควรเป็น O (N ^ 2) เช่น เชิงเส้นในขนาดอาร์เรย์

พาฉันไปสองสามชั่วโมงเพื่อไขปริศนาอันนี้ออกมา - ฉันไม่ต้องการที่จะเกิดขึ้นกับมันภายใต้แรงกดดันจากการสัมภาษณ์! ถ้าฉันทำบูบูฉันก็เหนื่อยเกินกว่าจะหามัน ...

อืม ... ฉันเลือกที่จะนิยาม "single-pass" เพื่อให้กวาดผ่านเมทริกซ์แทนที่จะแตะแต่ละค่าหนึ่งครั้ง! :-)

#include <stdio.h>
#include <memory.h>

#define SIZE    5

typedef unsigned char u8;

u8 g_Array[ SIZE ][ SIZE ];

void Dump()
{
    for ( int nRow = 0; nRow < SIZE; ++nRow )
    {
        for ( int nColumn = 0; nColumn < SIZE; ++nColumn )
        {
            printf( "%d ", g_Array[ nRow ][ nColumn ] );
        }
        printf( "\n" );
    }
}

void Process()
{
    u8 fCarriedAlpha = true;
    u8 fCarriedBeta = true;
    for ( int nStep = 0; nStep < SIZE; ++nStep )
    {
        u8 fAlpha = (nStep > 0) ? g_Array[ nStep-1 ][ nStep ] : true;
        u8 fBeta = (nStep > 0) ? g_Array[ nStep ][ nStep - 1 ] : true;
        fAlpha &= g_Array[ nStep ][ nStep ];
        fBeta &= g_Array[ nStep ][ nStep ];
        g_Array[ nStep-1 ][ nStep ] = fCarriedBeta;
        g_Array[ nStep ][ nStep-1 ] = fCarriedAlpha;
        for ( int nScan = nStep + 1; nScan < SIZE; ++nScan )
        {
            fBeta &= g_Array[ nStep ][ nScan ];
            if ( nStep > 0 )
            {
                g_Array[ nStep ][ nScan ] &= g_Array[ nStep-1 ][ nScan ];
                g_Array[ nStep-1][ nScan ] = fCarriedBeta;
            }

            fAlpha &= g_Array[ nScan ][ nStep ];
            if ( nStep > 0 )
            {
                g_Array[ nScan ][ nStep ] &= g_Array[ nScan ][ nStep-1 ];
                g_Array[ nScan ][ nStep-1] = fCarriedAlpha;
            }
        }

        g_Array[ nStep ][ nStep ] = fAlpha & fBeta;

        for ( int nScan = nStep - 1; nScan >= 0; --nScan )
        {
            g_Array[ nScan ][ nStep ] &= fAlpha;
            g_Array[ nStep ][ nScan ] &= fBeta;
        }
        fCarriedAlpha = fAlpha;
        fCarriedBeta = fBeta;
    }
}

int main()
{
    memset( g_Array, 1, sizeof(g_Array) );
    g_Array[0][1] = 0;
    g_Array[0][4] = 0;
    g_Array[1][0] = 0;
    g_Array[1][4] = 0;
    g_Array[3][1] = 0;

    printf( "Input:\n" );
    Dump();
    Process();
    printf( "\nOutput:\n" );
    Dump();

    return 0;
}

0

ฉันหวังว่าคุณจะสนุกกับโซลูชัน 1-pass c # ของฉัน

คุณสามารถดึงองค์ประกอบด้วย O (1) และต้องการพื้นที่เพียงหนึ่งแถวและหนึ่งคอลัมน์ของเมทริกซ์

bool[][] matrix =
{
    new[] { true, false, true, true, false }, // 10110
    new[] { false, true, true, true, false }, // 01110
    new[] { true, true, true, true, true },   // 11111
    new[] { true, false, true, true, true },  // 10111
    new[] { true, true, true, true, true }    // 11111
};

int n = matrix.Length;
bool[] enabledRows = new bool[n];
bool[] enabledColumns = new bool[n];

for (int i = 0; i < n; i++)
{
    enabledRows[i] = true;
    enabledColumns[i] = true;
}

for (int rowIndex = 0; rowIndex < n; rowIndex++)
{
    for (int columnIndex = 0; columnIndex < n; columnIndex++)
    {
        bool element = matrix[rowIndex][columnIndex];
        enabledRows[rowIndex] &= element;
        enabledColumns[columnIndex] &= element;
    }
}

for (int rowIndex = 0; rowIndex < n; rowIndex++)
{
    for (int columnIndex = 0; columnIndex < n; columnIndex++)
    {
        bool element = enabledRows[rowIndex] & enabledColumns[columnIndex];
        Console.Write(Convert.ToInt32(element));
    }
    Console.WriteLine();
}

/*
    00000
    00000
    00110
    00000
    00110
*/

ฉันคิดว่าปัญหาเดียวอาจเป็นเพราะคุณกำลังใช้ข้อมูลพิเศษสองอาร์เรย์เพื่อใช้งานนี้ หนึ่งในข้อกำหนดคือไม่ใช้หน่วยความจำเพิ่มเติม แต่ก็ดีนะ! นี้เป็นพื้นสิ่งที่ฉันได้ในคำตอบของฉัน :)
เคนนี Cason

0

1 ผ่าน 2 booleans ฉันแค่ต้องสมมติว่าดัชนีจำนวนเต็มในการวนซ้ำไม่นับ

นี่ไม่ใช่ทางออกที่สมบูรณ์ แต่ฉันไม่สามารถผ่านจุดนี้ไปได้

ถ้าฉันสามารถระบุได้ว่า 0 เป็น 0 ดั้งเดิมหรือ 1 ที่ถูกแปลงเป็น 0 ดังนั้นฉันจะไม่ต้องใช้ -1 และสิ่งนี้จะใช้ได้

ผลลัพธ์ของฉันเป็นเช่นนี้:

-1  0 -1 -1  0
 0 -1 -1 -1  0
-1 -1  1  1 -1
-1  0 -1 -1 -1
-1 -1  1  1 -1

ความคิดริเริ่มของวิธีการของฉันคือการใช้ครึ่งแรกของการตรวจสอบของแถวหรือคอลัมน์เพื่อตรวจสอบว่ามันมี 0 และครึ่งสุดท้ายเพื่อกำหนดค่า - ทำโดยดูจาก x และ width-x จากนั้น y และความสูง -y ในการวนซ้ำแต่ละครั้ง จากผลลัพธ์ของการทำซ้ำครึ่งแรกหากพบ 0 ในแถวหรือคอลัมน์ฉันใช้ครึ่งสุดท้ายของการทำซ้ำเพื่อเปลี่ยน 1's เป็น -1

ฉันเพิ่งรู้ว่าสิ่งนี้สามารถทำได้โดยมีเพียง 1 บูลีนเหลือ 1 ถึง ... ?

ฉันกำลังโพสต์สิ่งนี้โดยหวังว่าจะมีคนพูดว่า "อ่าทำสิ่งนี้ ... " (และฉันใช้เวลามากเกินไปที่จะไม่โพสต์)

นี่คือรหัสใน VB:

Dim D(,) As Integer = {{1, 0, 1, 1, 1}, {0, 1, 1, 0, 1}, {1, 1, 1, 1, 1}, {1, 1, 1, 1, 1}, {0, 0, 1, 1, 1}}

Dim B1, B2 As Boolean

For y As Integer = 0 To UBound(D)

    B1 = True : B2 = True

    For x As Integer = 0 To UBound(D)

        // Scan row for 0's at x and width - x positions. Halfway through I'll konw if there's a 0 in this row.
        //If a 0 is found set my first boolean to false.
        If x <= (Math.Ceiling((UBound(D) + 1) / 2) - 1) Then
            If D(x, y) = 0 Or D(UBound(D) - x, y) = 0 Then B1 = False
        End If

        //If the boolean is false then a 0 in this row was found. Spend the last half of this loop
        //updating the values. This is where I'm stuck. If I change a 1 to a 0 it will cause the column
        //scan to fail. So for now I change to a -1. If there was a way to change to 0 yet later tell if
        //the value had changed this would work.
        If Not B1 Then
            If x >= (Math.Ceiling((UBound(D) + 1) / 2) - 1) Then
                If D(x, y) = 1 Then D(x, y) = -1
                If D(UBound(D) - x, y) = 1 Then D(UBound(D) - x, y) = -1
            End If
        End If

        //These 2 block do the same as the first 2 blocks but I switch x and y to do the column.
        If x <= (Math.Ceiling((UBound(D) + 1) / 2) - 1) Then
            If D(y, x) = 0 Or D(y, UBound(D) - x) = 0 Then B2 = False
        End If

        If Not B2 Then
            If x >= (Math.Ceiling((UBound(D) + 1) / 2) - 1) Then
                If D(y, x) = 1 Then D(y, x) = -1
                If D(y, UBound(D) - x) = 1 Then D(y, UBound(D) - x) = -1
            End If
        End If

    Next
Next

0

ไม่มีใครใช้รูปแบบไบนารี? เนื่องจากมันมีเพียง 1 และ 0 เราสามารถใช้เวกเตอร์ไบนารี่ได้

def set1(M, N):
    '''Set 1/0s on M according to the rules.

    M is a list of N integers. Each integer represents a binary array, e.g.,
    000100'''
    ruler = 2**N-1
    for i,v in enumerate(M):
        ruler = ruler & M[i]
        M[i] = M[i] if M[i]==2**N-1 else 0  # set i-th row to all-0 if not all-1s
    for i,v in enumerate(M):
        if M[i]: M[i] = ruler
    return M

นี่คือการทดสอบ:

M = [ 0b10110,
      0b01110,
      0b11111,
      0b10111,
      0b11111 ]

print "Before..."
for i in M: print "{:0=5b}".format(i)

M = set1(M, len(M))
print "After..."
for i in M: print "{:0=5b}".format(i)

และผลลัพธ์:

Before...
10110
01110
11111
10111
11111
After...
00000
00000
00110
00000
00110

0

คุณสามารถทำสิ่งนี้เพื่อใช้หนึ่งผ่าน แต่เมทริกซ์อินพุตและเอาต์พุต:

output(x,y) = col(xy) & row(xy) == 2^n

โดยที่col(xy)บิตในคอลัมน์บรรจุจุดxyนั้น เป็นบิตในแถวที่มีการจุดrow(xy) คือขนาดของเมทริกซ์xyn

จากนั้นก็วนซ้ำอินพุต อาจขยายได้เพื่อให้มีพื้นที่มากขึ้นหรือไม่


0

หนึ่งเมทริกซ์สแกนสองบูลีนไม่มีการเรียกซ้ำ

วิธีการหลีกเลี่ยงการผ่านครั้งที่สอง? ต้องผ่านครั้งที่สองเพื่อล้างแถวหรือคอลัมน์เมื่อศูนย์ปรากฏที่จุดสิ้นสุด

อย่างไรก็ตามปัญหานี้สามารถแก้ไขได้เนื่องจากเมื่อเราสแกนแถว #i เรารู้สถานะแถวของแถว # i-1 แล้ว ดังนั้นในขณะที่เรากำลังสแกนแถว #i เราสามารถล้างแถว # i-1 ได้พร้อมกันหากจำเป็น

โซลูชันเดียวกันใช้งานได้กับคอลัมน์ แต่เราต้องสแกนแถวและคอลัมน์พร้อมกันในขณะที่ข้อมูลจะไม่เปลี่ยนไปในการทำซ้ำครั้งถัดไป

สองบูลีนจะต้องเก็บสถานะของแถวแรกและคอลัมน์แรกเนื่องจากค่าของพวกเขาจะเปลี่ยนไปในระหว่างการดำเนินการของส่วนหลักของอัลกอริทึม

เพื่อหลีกเลี่ยงการเพิ่มบูลีนเพิ่มเติมเรากำลังจัดเก็บค่าสถานะ "ชัดเจน" สำหรับแถวและคอลัมน์ในแถวแรกและคอลัมน์ของเมทริกซ์

public void Run()
{
    const int N = 5;

    int[,] m = new int[N, N] 
                {{ 1, 0, 1, 1, 0 },
                { 1, 1, 1, 1, 0 },
                { 1, 1, 1, 1, 1 },
                { 1, 0, 1, 1, 1 },
                { 1, 1, 1, 1, 1 }};

    bool keepFirstRow = (m[0, 0] == 1);
    bool keepFirstColumn = keepFirstRow;

    for (int i = 1; i < N; i++)
    {
        keepFirstRow = keepFirstRow && (m[0, i] == 1);
        keepFirstColumn = keepFirstColumn && (m[i, 0] == 1);
    }

    Print(m); // show initial setup

    m[0, 0] = 1; // to protect first row from clearing by "second pass"

    // "second pass" is performed over i-1 row/column, 
    // so we use one more index just to complete "second pass" over the 
    // last row/column
    for (int i = 1; i <= N; i++)
    {
        for (int j = 1; j <= N; j++)
        {
            // "first pass" - searcing for zeroes in row/column #i
            // when i = N || j == N it is additional pass for clearing 
            // the previous row/column
            // j >= i because cells with j < i may be already modified 
            // by "second pass" part
            if (i < N && j < N && j >= i) 
            {
                m[i, 0] &= m[i, j];
                m[0, j] &= m[i, j];

                m[0, i] &= m[j, i];
                m[j, 0] &= m[j, i];
            }

            // "second pass" - clearing the row/column scanned 
            // in the previous iteration
            if (m[i - 1, 0] == 0 && j < N)
            {
                m[i - 1, j] = 0;
            }

            if (m[0, i - 1] == 0 && j < N)
            {
                m[j, i - 1] = 0;
            }
        }

        Print(m);
    }

    // Clear first row/column if needed
    if (!keepFirstRow || !keepFirstColumn)
    {
        for (int i = 0; i < N; i++)
        {
            if (!keepFirstRow)
            {
                m[0, i] = 0;
            }
            if (!keepFirstColumn)
            {
                m[i, 0] = 0;
            }
        }
    }

    Print(m);

    Console.ReadLine();
}

private static void Print(int[,] m)
{
    for (int i = 0; i < m.GetLength(0); i++)
    {
        for (int j = 0; j < m.GetLength(1); j++)
        {
            Console.Write(" " + m[i, j]);
        }
        Console.WriteLine();
    }
    Console.WriteLine();
}

0

ดูเหมือนว่างานต่อไปนี้จะไม่มีข้อกำหนดด้านพื้นที่เพิ่มเติม:

สิ่งแรกคือการคูณองค์ประกอบของแถวคูณกับองค์ประกอบของบรรทัดที่องค์ประกอบนั้นให้ค่าที่ต้องการ

เพื่อไม่ให้ใช้พื้นที่เพิ่มเติมใด ๆ (ไม่ได้สร้างเมทริกซ์ใหม่และเติมให้เต็ม แต่แทนที่จะใช้การเปลี่ยนแปลงเมทริกซ์โดยตรง) ให้เริ่มด้านบนซ้ายของเมทริกซ์และทำการคำนวณสำหรับเมทริกซ์ ixi ใด ๆ (ที่ "เริ่มต้น" ที่ (0 0)) ก่อนพิจารณาองค์ประกอบใด ๆ ที่มีดัชนี> i

หวังว่างานนี้ (havent testet)


ดูเหมือนว่าจะไม่ถูกต้อง สมมติว่าแถว 0 มีเพียง 1 ค่า หากค่าสุดท้ายที่คุณกำหนดไว้สำหรับ (0,0) เป็น 0 คุณจะตั้งค่าแถวที่สมบูรณ์เป็น 0 ซึ่งไม่จำเป็นต้องแก้ไขในภายหลัง คุณจำเป็นต้องเก็บค่า 2 ต่อเซลล์เพื่อทำรูปแบบการเขียนโปรแกรมแบบไดนามิกโดยใช้หลักการของคุณ
Eyal Schneider

แน่นอนว่าคุณพูดถูก แทนที่จะเก็บค่าสองค่าฉันสามารถใช้ posibility ลำดับที่สามได้เช่น -1 ซึ่งหมายถึงเซลล์ที่มี 1 ในเมทริกซ์ "เก่า" ซึ่งในที่สุดจะถูกแทนที่ด้วย 0 แน่นอนวิธีนั้นต้องใช้ค่าสัมบูรณ์ ค่าหลังจากการคูณ ในท้ายที่สุดทั้งหมด -1 จะถูกแทนที่ด้วย 0
DFF

0

นี่คือการทดสอบสำหรับ N ที่แตกต่างกันใน C ++ และคือ:
หนึ่งผ่าน , สองบูล , ไม่มีการเรียกซ้ำ , ไม่มีหน่วยความจำพิเศษ , หลุมสำหรับการ N ขนาดใหญ่โดย
ไม่ได้ตั้งใจ

โดยเฉพาะอย่างยิ่งฉันสนุกเคาน์เตอร์สองวงไม่เป็นไร ฉันมีสองกลุ่มที่ไม่ได้ลงชื่อซึ่งมีอยู่มากกว่าการคำนวณทุกครั้งเพื่อให้สามารถอ่านได้ ช่วงเวลาของลูปภายนอกคือ [0, N] และช่วงเวลาของลูปด้านในคือ [1, n - 1] คำสั่ง switch อยู่ในลูปส่วนใหญ่มีอยู่เพื่อแสดงอย่างชัดเจนว่ามันเป็นเพียงหนึ่งผ่าน

กลยุทธ์อัลกอริทึม:

เคล็ดลับแรกคือให้เราหนึ่งแถวและหนึ่งคอลัมน์จากเมทริกซ์ตัวเองเพื่อรวบรวมเนื้อหาของเมทริกซ์หน่วยความจำนี้จะพร้อมใช้งานโดยการถ่ายทั้งหมดที่เราต้องรู้จากแถวแรกและคอลัมน์เป็นสองบูลีน เคล็ดลับที่สองคือการได้รับสองผ่านจากหนึ่งโดยใช้สมมาตรของเมทริกซ์ย่อยและดัชนี

เรื่องย่อของอัลกอริทึม:

  • สแกนแถวแรกและเก็บถ้าเป็นทั้งหมดในบูลีนทำเช่นเดียวกันสำหรับคอลัมน์แรกที่เก็บผลลัพธ์ในบูลีนที่สอง
  • สำหรับเมทริกซ์ย่อยที่ไม่รวมแถวแรกและคอลัมน์แรก: วนซ้ำไปเรื่อย ๆ จากซ้ายไปขวาบนลงล่างเนื่องจากจะอ่านหนึ่งย่อหน้า เมื่อเยี่ยมชมแต่ละองค์ประกอบให้เยี่ยมชมองค์ประกอบที่เกี่ยวข้องที่จะเยี่ยมชมหากเยี่ยมชม sub-matrix ในสิ่งที่ตรงกันข้าม สำหรับแต่ละองค์ประกอบที่เข้าชมและค่าของมันลงในตำแหน่งที่แถวของมันข้ามคอลัมน์แรกและยังและมูลค่าของมันไปยังที่ที่คอลัมน์นั้นข้ามแถวแรก
  • เมื่อถึงจุดกึ่งกลางของเมทริกซ์ย่อยแล้วให้ไปที่องค์ประกอบทั้งสองพร้อมกันดังที่กล่าวมาข้างต้น อย่างไรก็ตามในตอนนี้ให้ตั้งค่าอิลิเมนต์ที่เยี่ยมชมเป็น AND ของที่แถวนั้นข้ามคอลัมน์แรกและที่คอลัมน์นั้นข้ามแถวแรก หลังจากนี้เมทริกซ์ย่อยจะเสร็จสมบูรณ์
  • ใช้ตัวแปรบูลีนสองตัวคำนวณที่ขอทานเพื่อตั้งค่าแถวแรกและคอลัมน์แรกเป็นค่าที่ถูกต้อง

Templatized การใช้ C ++:

template<unsigned n>
void SidewaysAndRowColumn(int((&m)[n])[n]) {
    bool fcol = m[0][0] ? true : false;
    bool frow = m[0][0] ? true : false;
    for (unsigned d = 0; d <= n; ++d) {
        for (unsigned i = 1; i < n; ++i) {
            switch (d) {
                case 0:
                    frow    = frow && m[d][i];
                    fcol    = fcol && m[i][d];
                    break;
                default:
                {
                    unsigned const rd = n - d;
                    unsigned const ri = n - i;
                    if (d * n + i < rd * n + ri)
                    {
                        m[ d][ 0] &= m[ d][ i];
                        m[ 0][ d] &= m[ i][ d];
                        m[ 0][ i] &= m[ d][ i];
                        m[ i][ 0] &= m[ i][ d];
                        m[rd][ 0] &= m[rd][ri];
                        m[ 0][rd] &= m[ri][rd];
                        m[ 0][ri] &= m[rd][ri];
                        m[ri][ 0] &= m[ri][rd];
                    }
                    else
                    {
                        m[ d][ i] = m[ d][0] & m[0][ i];
                        m[rd][ri] = m[rd][0] & m[0][ri];
                    }
                    break;
                }
                case n:
                    if (!frow)
                        m[0][i] = 0;
                    if (!fcol)
                        m[i][0] = 0;
            };
        }
    }
    m[0][0] = (frow && fcol) ? 1 : 0;
}

0

ตกลงฉันรู้ว่ามันไม่ใช่การแข่งขัน แต่ฉันได้รับในครั้งเดียวโดยใช้บูลและไบต์แทนสองคนโง่ ... ปิด ฉันจะไม่รับรองประสิทธิภาพของมัน แต่คำถามประเภทนี้มักจะต้องการโซลูชันที่ดีที่สุด

private static void doIt(byte[,] matrix)
{
    byte zeroCols = 0;
    bool zeroRow = false;

    for (int row = 0; row <= matrix.GetUpperBound(0); row++)
    {
        zeroRow = false;
        for (int col = 0; col <= matrix.GetUpperBound(1); col++)
        {
            if (matrix[row, col] == 0)
            {

                zeroRow = true;
                zeroCols |= (byte)(Math.Pow(2, col));

                // reset this column in previous rows
                for (int innerRow = 0; innerRow < row; innerRow++)
                {
                    matrix[innerRow, col] = 0;
                }

                // reset the previous columns in this row
                for (int innerCol = 0; innerCol < col; innerCol++)
                {
                    matrix[row, innerCol] = 0;
                }
            }
            else if ((int)(zeroCols & ((byte)Math.Pow(2, col))) > 0)
            {
                matrix[row, col] = 0;
            }

            // Force the row to zero
            if (zeroRow) { matrix[row, col] = 0; }
        }
    }
}

0

คุณสามารถเรียงลำดับได้ในครั้งเดียว - หากคุณไม่นับการเข้าถึงเมทริกซ์ในลำดับการเข้าถึงแบบสุ่มซึ่งจะขจัดข้อดีของการทำแบบ Single-pass ในครั้งแรก (cache-coherence / memory-bandwidth)

[แก้ไข: ลบโซลูชันที่เรียบง่าย แต่ไม่ถูกต้อง]

คุณควรจะได้ประสิทธิภาพที่ดีกว่าวิธี single-pass ใด ๆ โดยทำสองรอบ: วิธีหนึ่งในการรวบรวมข้อมูลแถว / คอลัมน์และอีกวิธีหนึ่งในการปรับใช้ อาร์เรย์ (ตามลำดับแถวลำดับหลัก) มีการเข้าถึงอย่างต่อเนื่อง สำหรับอาร์เรย์ที่มีขนาดเกินขนาดแคช (แต่แถวที่มีขนาดพอดีกับแคช) ควรอ่านข้อมูลจากหน่วยความจำสองครั้งและจัดเก็บหนึ่งครั้ง:

void fixmatrix2(int M[][], int rows, int cols) {
    bool clearZeroRow= false;
    bool clearZeroCol= false;
    for(int j=0; j < cols; ++j) {
        if( ! M[0][j] ) {
            clearZeroRow= true;
        }
    }
    for(int i=1; i < rows; ++i) { // scan/accumulate pass
        if( ! M[i][0] ) {
            clearZeroCol= true;
        }
        for(int j=1; j < cols; ++j) {
            if( ! M[i][j] ) {
                M[0][j]= 0;
                M[i][0]= 0;
            }
        }
    }
    for(int i=1; i < rows; ++i) { // update pass
        if( M[i][0] ) {
            for(int j=0; j < cols; ++j) {
                if( ! M[j][0] ) {
                    M[i][j]= 0;
                }
            }
        } else {
            for(int j=0; j < cols; ++j) {
                M[i][j]= 0;
            }
        }
        if(clearZeroCol) {
            M[i][0]= 0;
        }
    }
    if(clearZeroRow) {
        for(int j=0; j < cols; ++j) {
            M[0][j]= 0;
        }
    }
}

0

ทางออกที่ง่ายที่สุดที่ฉันนึกได้คือวางไว้ด้านล่าง ตรรกะคือการบันทึกแถวและคอลัมน์ที่จะตั้งศูนย์ในขณะที่วนซ้ำ

import java.util.HashSet;
import java.util.Set;

public class MatrixExamples {
    public static void zeroOut(int[][] myArray) {
        Set<Integer> rowsToZero = new HashSet<>();
        Set<Integer> columnsToZero = new HashSet<>();

        for (int i = 0; i < myArray.length; i++) { 
            for (int j = 0; j < myArray.length; j++) {
                if (myArray[i][j] == 0) {
                    rowsToZero.add(i);
                    columnsToZero.add(j);
                }
            }
        }

        for (int i : rowsToZero) {
            for (int j = 0; j < myArray.length; j++) {
                myArray[i][j] = 0;
            }
        }

        for (int i : columnsToZero) {
            for (int j = 0; j < myArray.length; j++) {
                myArray[j][i] = 0;
            }
        }

        for (int i = 0; i < myArray.length; i++) { // record which rows and                                             // columns will be zeroed
            for (int j = 0; j < myArray.length; j++) {
                System.out.print(myArray[i][j] + ",");
            if(j == myArray.length-1)
                System.out.println();
            }
        }

    }

    public static void main(String[] args) {
        int[][] a = { { 1, 0, 1, 1, 0 }, { 0, 1, 1, 1, 0 }, { 1, 1, 1, 1, 1 },
                { 1, 0, 1, 1, 1 }, { 1, 1, 1, 1, 1 } };
        zeroOut(a);
    }
}

0

นี่คือการติดตั้ง Ruby ของฉันพร้อมกับการทดสอบซึ่งจะใช้พื้นที่ O (MN) ถ้าเราต้องการให้มีการปรับปรุงเวลาจริง (ชอบที่จะแสดงผลเมื่อเราพบศูนย์แทนที่จะรอวงแรกของการหาศูนย์) เราก็สามารถสร้างตัวแปรชั้นอื่นเช่น@outputและเมื่อใดก็ตามที่เราพบว่ามีการปรับปรุงศูนย์เราและไม่ได้@output@input

require "spec_helper"


class Matrix
    def initialize(input)
        @input  = input
        @zeros  = []
    end

    def solve
        @input.each_with_index do |row, i|          
            row.each_with_index do |element, j|                             
                @zeros << [i,j] if element == 0
            end
        end

        @zeros.each do |x,y|
            set_h_zero(x)
            set_v_zero(y)
        end

        @input
    end


    private 

    def set_h_zero(row)     
        @input[row].map!{0}     
    end

    def set_v_zero(col)
        @input.size.times do |r|
            @input[r][col] = 0
        end
    end
end


describe "Matrix" do
  it "Should set the row and column of Zero to Zeros" do
    input =  [[1, 3, 4, 9, 0], 
              [0, 3, 5, 0, 8], 
              [1, 9, 6, 1, 9], 
              [8, 3, 2, 0, 3]]

    expected = [[0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0],
                [0, 9, 6, 0, 0],
                [0, 0, 0, 0, 0]]

    matrix = Matrix.new(input)

    expect(matrix.solve).to eq(expected)
  end
end

0

รหัสด้านล่างสร้างเมทริกซ์ขนาด m, n ก่อนอื่นตัดสินใจขนาดของเมทริกซ์ ฉันต้องการเติมเมทริกซ์ [m] [n] ด้วยการสุ่มด้วยตัวเลขระหว่าง 0..10 จากนั้นสร้างเมทริกซ์อื่นที่มีขนาดเดียวกันและเติมด้วย -1s (เมทริกซ์สุดท้าย) จากนั้นวนซ้ำเมทริกซ์เริ่มต้นเพื่อดูว่าคุณจะตี 0 หรือไม่เมื่อคุณกดที่ตำแหน่ง (x, y) ให้ไปที่เมทริกซ์สุดท้ายและเติมแถว x ด้วย 0s และคอลัมน์ y ด้วย 0s ในตอนท้ายอ่านเมทริกซ์สุดท้ายหากค่าเป็น -1 (ค่าดั้งเดิม) ให้คัดลอกค่าในตำแหน่งเดียวกันของเมทริกซ์เริ่มต้นไปจนถึงขั้นสุดท้าย

public static void main(String[] args) {
    int m = 5;
    int n = 4;
    int[][] matrixInitial = initMatrix(m, n); // 5x4 matrix init randomly
    int[][] matrixFinal = matrixNull(matrixInitial, m, n); 
    for (int i = 0; i < m; i++) {
        System.out.println(Arrays.toString(matrixFinal[i]));
    }
}

public static int[][] matrixNull(int[][] matrixInitial, int m, int n) {
    int[][] matrixFinal = initFinal(m, n); // create a matrix with mxn and init it with all -1
    for (int i = 0; i < m; i++) { // iterate in initial matrix
        for (int j = 0; j < n; j++) {
            if(matrixInitial[i][j] == 0){ // if a value is 0 make rows and columns 0
                makeZeroX(matrixFinal, i, j, m, n); 
            }
        }
    }

    for (int i = 0; i < m; i++) { // if value is -1 (original) copy from initial
        for (int j = 0; j < n; j++) {
            if(matrixFinal[i][j] == -1) {
                matrixFinal[i][j] = matrixInitial[i][j];
            }
        }
    }
    return matrixFinal;
}

private static void makeZeroX(int[][] matrixFinal, int x, int y, int m, int n) {
        for (int j = 0; j < n; j++) { // make all row 0
            matrixFinal[x][j] = 0;
        }
        for(int i = 0; i < m; i++) { // make all column 0
            matrixFinal[i][y] = 0; 
        }
}

private static int[][] initMatrix(int m, int n) {

    int[][] matrix = new int[m][n];
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            Random rn = new Random();
            int random = rn.nextInt(10);
            matrix[i][j] = random;
        }
    }

    for (int i = 0; i < m; i++) {
        System.out.println(Arrays.toString(matrix[i]));
    }
    System.out.println("******");
    return matrix;
}

private static int[][] initFinal(int m, int n) {

    int[][] matrix = new int[m][n];
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            matrix[i][j] = -1;
        }
    }
    return matrix;
}

// another approach
/**
 * @param matrixInitial
 * @param m
 * @param n
 * @return
 */
private static int[][] matrixNullNew(int[][] matrixInitial, int m, int n) {
    List<Integer> zeroRowList = new ArrayList<>(); // Store rows with 0
    List<Integer> zeroColumnList = new ArrayList<>(); // Store columns with 0
    for (int i = 0; i < m; i++) { // read through the matrix when you hit 0 add the column to zeroColumnList and add
                                  // the row to zeroRowList
        for (int j = 0; j < n; j++) {
            if (matrixInitial[i][j] == 0) {
                if (!zeroRowList.contains(i)) {
                    zeroRowList.add(i);
                }
                if (!zeroColumnList.contains(j)) {
                    zeroColumnList.add(j);
                }
            }
        }
    }

    for (int a = 0; a < m; a++) {
        if (zeroRowList.contains(a)) { // if the row has 0
            for (int b = 0; b < n; b++) {
                matrixInitial[a][b] = 0; // replace all row with zero
            }
        }
    }

    for (int b = 0; b < n; b++) {
        if (zeroColumnList.contains(b)) { // if the column has 0
            for (int a = 0; a < m; a++) {
                matrixInitial[a][b] = 0; // replace all column with zero
            }
        }
    }
    return matrixInitial;
}

คุณไม่ได้ให้คำอธิบายหรือบริบทใด ๆ กับรหัสที่คุณโพสต์
แอรอน

หวังว่าจะดีขึ้นแล้ว ขอบคุณสำหรับคำเตือน ฉันต้องการอธิบายเพิ่มเติมหากไม่ชัดเจนสำหรับคุณ
3743369

0

นี่คือทางออกของฉัน อย่างที่คุณเห็นจากรหัสเมื่อให้เมทริกซ์ M * N มันจะกำหนดทั้งแถวเป็นศูนย์เมื่อตรวจสอบศูนย์ในแถวนั้นความซับซ้อนของเวลาในการแก้ปัญหาของฉันคือ O (M * N) ฉันกำลังแบ่งปันคลาสทั้งหมดซึ่งมีอาร์เรย์ที่มีประชากรคงที่สำหรับการทดสอบและวิธีการแสดงอาร์เรย์เพื่อดูผลลัพธ์ในคอนโซล

public class EntireRowSetToZero {
    static int arr[][] = new int[3][4];
    static {

    arr[0][0] = 1;
    arr[0][1] = 9;
    arr[0][2] = 2;
    arr[0][3] = 2;

    arr[1][0] = 1;
    arr[1][1] = 5;
    arr[1][2] = 88;
    arr[1][3] = 7;

    arr[2][0] = 0;
    arr[2][1] = 8;
    arr[2][2] = 4;
    arr[2][3] = 4;
}

public static void main(String[] args) {
    displayArr(EntireRowSetToZero.arr, 3, 4);
    setRowToZero(EntireRowSetToZero.arr);
    System.out.println("--------------");
    displayArr(EntireRowSetToZero.arr, 3, 4);


}

static int[][] setRowToZero(int[][] arr) {
    for (int i = 0; i < arr.length; i++) {
        for (int j = 0; j < arr[i].length; j++) {
            if(arr[i][j]==0){
                arr[i]=new int[arr[i].length];
            }
        }

    }
    return arr;
}

static void displayArr(int[][] arr, int n, int k) {

    for (int i = 0; i < n; i++) {

        for (int j = 0; j < k; j++) {
            System.out.print(arr[i][j] + " ");
        }
        System.out.println("");
    }

}

}

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.